陈明灿-第二次作业

这个作业属于哪个课程 至诚软工实践F班
这个作业要求在哪里 第二次作业
这个作业的目标 使用fiddler抓包工具抓去数据,并进行解析
Github 地址 Github地址

第二次作业:个人编程

一、实时监控朴朴上某产品的详细价格信息

【必做】基础:使用 fiddler 抓包工具+代码,实时监控朴朴上某产品的详细价格信息

解题思路

在获得题目时,首先明确自己所需要使用的工具

  • 1、fiddler-- 抓包工具,可以将网络传输发送与接收的数据包进行截获、重发、编辑等操作。
  • 2、浏览器--开发者工具,NetWork:从发起网页页面请求Request后分析HTTP请求后得到的各个请求资源信息
  • 3、安卓模拟器--使用夜神模拟器

实现过程

​ 首先安装好fiddler 后我们需要进行一些系统的配置,由于校园网限制代理服务器,所以采用移动热点继续进行,首先我们获取本地的ipv4地址,进入命令控制符使用指令获取

WIN+R->cmd->ipconfig
  • [ ]

​ fiddler 的配置,打开连接及安装证书

位置:Tools->Options->Connections


​ 配置完成后我们使用夜神模拟器,添加网络代理,在我们添加代理后,可以尝试打开APP操作来进行抓包,此时可能会有APP限制抓包【禁用网络】,原因及解决方法在下面

在使用抓包工具进行抓包时,我们可能会遇到APP没有网络等原因,很大可能是因为所配置的证书不被信任,所以我们可以禁止SSL证书验证来破解APP的抓包限制,要解决这个问题要使用的工具是:Xposed+JustTrustMe

XposedInstaller(xposed框架)是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。而JustTrustMe是Github上的一个开源工程,他是一个Xposed模块,用来禁止SSL证书验证。【夜神模拟器有提供安装包进行下载配置】

​ 现在准备工作就已经完成,我们可以开始正式的进行APP抓包,我们打开朴朴选择一个产品,在fiddler中可以看到接口信息及返回信息

​ 此刻,我们已经获取到朴朴商品的接口信息,接口信息如下:

接口地址

https://j1.pupuapi.com/client/product/storeproduct/detail/7c1208da-907a-4391-9901-35a60096a3f9/714c63f8-075d-4d20-b69c-246ac48d9da1

请求头:

pp-version: 2021062503
pp_storeid: 7c1208da-907a-4391-9901-35a60096a3f9
pp-placeid: ad79346d-7856-4c68-b2c9-ac323a8f949e
User-Agent: Pupumall/3.5.6;Android/7.1.2;d7565c13d951a42f117e267a53da5583
pp-userid: 9c3aa45f-b8ae-4b3b-8312-ec955a3cf0da
pp-os: 10
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIiLCJhdWQiOiJodHRwczovL3VjLnB1cHVhcGkuY29tIiwiaXNfbm90X25vdmljZSI6IjAiLCJpc3MiOiJodHRwczovL3VjLnB1cHVhcGkuY29tIiwiZ2l2ZW5fbmFtZSI6IjEzMzU4NTkzMTA5IiwiZXhwIjoxNjQ3MzU4MDE4LCJ2ZXJzaW9uIjoiMi4wIiwianRpIjoiOWMzYWE0NWYtYjhhZS00YjNiLTgzMTItZWM5NTVhM2NmMGRhIn0.PKwOKHLWe7N6tKUe28HhXeqmJNbiNWtoa79Jxfepr-w
X-B3-TraceId: 52cd9c18efe60e40
X-B3-SpanId: f0d5df9eb2873650
Host: j1.pupuapi.com
Connection: Keep-Alive
Accept-Encoding: gzip

我们可以使用任意编程语言进行解析,该题采用python,如下

"""
监控朴朴上某产品的详细价格信息
"""
import requests
import time


# 获得商品详情json
def getProduct():
    url = "https://j1.pupuapi.com/client/product/storeproduct/detail/7c1208da-907a-4391-9901-35a60096a3f9/97721095-5c55-4746-bd9e-8c98ef2946a3"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36'
    }
    result = requests.get(url=url, headers=headers)
    data = result.json()['data']
    return data


# 获得商品名
def getName(result):
    return result['name']


# 获得产品规格
def getSpec(result):
    return result['spec']


# 获得现价
def getPrice(result):
    return float(result['price']) / 100


# 获得原价
def getMarketPrice(result):
    return float(result['market_price']) / 100


# 获得详细内容
def getShareContent(result):
    return result['share_content']


# 获得实时价格
def nowPrice():
    return float(getProduct()['price']) / 100


if __name__ == '__main__':
    # 调用接口,获得商品数据
    proData = getProduct()
    # 获得商品名称
    proName = getName(proData)
    # 获得产品规格
    proSpec = getSpec(proData)
    # 获得产品现价
    proPrice = getPrice(proData)
    # 获取产品原价
    proMarketPrice = getMarketPrice(proData)
    # 获取产品详细内容
    proContent = getShareContent(proData)
    print('-------------商品:%s-------------' % proName)
    print('规格:%s' % proSpec)
    print('价格:%.1f' % proPrice)
    print('折扣价/原价:%.1f/%.1f' % (proPrice, proMarketPrice))
    print('详细内容:%s\n' % proContent)
    print('-------------"%s"的价格波动-------------' % proName)
    # 循环获取目前价格
    while True:
        # 获得当前时间
        dateTime = time.strftime("%Y-%m-%d %H:%M:%S" , time.localtime())
        print('当前时间为%s,价格为%.1f' % (dateTime, nowPrice()))
        time.sleep(1)

当运行该文件时,控制台输出结果如下:

在项目进行调试,我们能够发现以下问题:

  • 当接口在同ip下短时间内多次调用,我们会遇到ip被封禁的情况,我们可以采用以下方法进行规避:
    • 更换User-Agent
    • 使用多个代理IP进行抓包

二、爬取自己的知乎收藏夹,以每个收藏夹的名称为大类,其下展示各个具体收藏文章的名称及其链接。

​ 面对这题,没有使用fiddler进行抓包,我们可以通过浏览器开发者工具中的network进行监控数据的传输,打开开发者工具【F12】后我们可以找到network。

​ 在我们进入页面时,network可以监听数据的传输,此时我们进入个人页面可以找到收藏夹的接口

接口地址:https://www.zhihu.com/api/v4/people/mu-shang-zhu-42/collections

​ 我们可以得知该接口通过GET进行调用,可将接口地址复制到浏览器中进行查看,此时浏览器页面中会加载调用接口返回的json数据,如下:

​ 此接口我们主要的目的是获取所有收藏夹的名称及id可通过json数据查看该数据对应的key为id及title,获取到id后我们可以再次进行接口的获取,此时点击进入某个收藏夹的页面,可以获取到收藏夹内所有收藏文章的接口

接口地址:https://www.zhihu.com/api/v4/collections/790047190/items
其中790047190为我们由上个接口获取到的收藏夹id

​ 同样,我们将它放到浏览器中,可以清楚的查看json数据

​ 我们可以在其中清楚的看到我们所需要的数据,标题和链接,此刻我们就可以使用python去进行数据的爬取及解析,但在此前,我们需要考虑的是收藏文章的类型,在进行检验时可以发现,收藏的分为两种类型【文章和问答】,而问答所获取的json数据和文章有所不同,如下:

此为收藏文章的json数据:
content: {
	id: 465502906,
	title: "台湾地区所有军事营区盘点",
	type: "article",
    .......
	url: "https://zhuanlan.zhihu.com/p/465502906",
    .......
}
此为收藏问答的json数据:
content: {
	id: 2382903605,
	type: "answer",
	answer_type: "NORMAL",
	url: "https://www.zhihu.com/question/520705594/answer/2382903605",
	created_time: 1646898142,
	updated_time: 1646898391,
	question: {
		type: "question",
		id: 520705594,
		title: "应届生加了 HR 的微信,应该称呼她为什么?",
		question_type: "normal",
		created: 1646708241,
		updated_time: 1646879369,
		url: "https://www.zhihu.com/question/520705594",
},

由上我们可以清楚的看到,如果是问题的标题,它会存储在content->question中,所以再用python进行爬取、解析数据的时候我们应该添加判断

articleTitle = article['content']['title']
	if articleTitle=='':
    	articleTitle = article['content']['question']['title']

​ 以上分析完毕,可以开始编写代码:

import requests


# 获得用户数据
def getUserDate():
    url = 'https://www.zhihu.com/api/v4/people/mu-shang-zhu-42/collections'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
        # 如果要获取自己私有的收藏夹,需要添加cookie
        # 'cookie':''
    }
    res = requests.get(url=url, headers=headers)
    return res.json()


if __name__ == '__main__':
    userDate=getUserDate()
    for colData in userDate['data']:
        print('------------收藏夹标题:【%s】------------'%colData['title'])
        url = "https://www.zhihu.com/api/v4/collections/%s/items" % colData['id']
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
        }
        res = requests.get(url=url, headers=headers).json()
        i=1
        for article in res['data']:
            articleTitle = article['content']['title']
            if articleTitle=='':
                articleTitle = article['content']['question']['title']
            articleLink = article['content']['url']
            print('--%s:%s\t%s' % (i,articleTitle, articleLink))
            i+=1
            

运行结果如下:

三、爬取拉勾网某个职位,某个公司规模,在某个城市的应届生薪资信息,并按照同等条件下,展示不同城市的应届生主要薪资范围分布情况。

​ 进入拉勾网网站使用开发者工具进行网络数据的传输监控,可以发现拉勾网的接口的信息

​ 该接口采用POST提交的方式,其中一些基本的选择信息【如地点、工作经验、学历等】存放在url params,而其他的数据【搜索内容,页码】存放在data中进行提交,提交请求后能够获得JSON数据,结构大致如下:

{
	"success": true,
	"msg": null,
	"code": 0,
	"content": {
		"positionResult": {
			"resultSize": 15,
			"result": [{
				"positionId": 9351115,
				"positionName": "2022届总部科技管培生(后端开发)",
				......
			}, 
		},
		"pageSize": 15
	},
	"resubmitToken": null,
	"requestId": null
}

​ 可以发现,我们需要的数据存放在content->positionResult->result中,可以使用那个代码进行json解析并输出,代码如下:

import requests
from pyecharts.charts import Bar
import pyecharts.options as opts
import re

class CityData(object):
    def __init__(self,salary):
        self.__salary=salary
        self.__count=0
    def addCount(self):
        self.__count+=1
    def getSalary(self):
        return self.__salary
    def getCount(self):
        return self.__count

list=[]

def getData(page,city):
    url = "https://www.lagou.com/jobs/positionAjax.json?gj=在校/应届&px=default&gm=50-150人&city=%s&needAddtionalResult=false"%city
    headers = {
        'accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Content-Length': '25',
        'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Host': 'www.lagou.com',
        'Origin': 'https://www.lagou.com',
        'Referer': 'https://www.lagou.com/jobs/list_java/p-city_0?&cl=false&fromSearch=true&labelWords=&suginput=',
        'sec-ch-ua':'" Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"',
        'sec-ch-ua-mobile':'?0',
        'sec-ch-ua-platform':'"Windows"',
        'Sec-Fetch-Dest':'empty',
        'Sec-Fetch-Mode':'cors',
        'Sec-Fetch-Site':'same-origin',
        'traceparent':'00-06bc3b8a19f3c6e98fe7c56d9adcae1d-4ba823c5c818d9e9-01',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
        'x-anit-forge-code': '0',
        'x-anit-forge-token': 'None',
        'x-requested-with': 'XMLHttpRequest',
        'cookie':'RECOMMEND_TIP=true; privacyPolicyPopup=false; _ga=GA1.2.1516507538.1647096956; user_trace_token=20220312225557-abb182ce-3f92-4651-9c39-31ebb4c7bdfe; LGUID=20220312225557-bfa9a12c-1d6b-4ade-b9e6-dc95c59fde8b; index_location_city=%E5%85%A8%E5%9B%BD; LG_HAS_LOGIN=1; hasDeliver=0; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; _gid=GA1.2.2010130206.1647242956; __lg_stoken__=18ffbcf2b7cde16a48df0c80069759da64ed5d3427729eae87b1361b2b93ca241428d2ab358fc4b718c2b81d7decdd559a6de084027f5186c937c0190a93eda797ccccb64bc2; JSESSIONID=ABAAABAABAGABFA2095E281A00B43C351EE0D9C94CFC176; WEBTJ-ID=20220315163755-17f8cba0528482-0092a2ae47748d-977173c-2073600-17f8cba0529ca8; LGSID=20220315163755-9896ef8f-e708-40b9-bf90-ecce6c733ae5; PRE_UTM=; PRE_HOST=; PRE_SITE=https%3A%2F%2Fwww.lagou.com; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2Fjobs%2Flist%5Fjava%2Fp-city%5F0%3F%26cl%3Dfalse%26fromSearch%3Dtrue%26labelWords%3D%26suginput%3D; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1647096956,1647242956,1647333476; gate_login_token=71c896588f9d88913074ddb57f208ae34641bab2fbec2a76d1a12fb63ec712ba; LG_LOGIN_USER_ID=2234f9799e36703943b23a21a509e8f4687aa0619f3e24f8880f5ebf36b5544f; _putrc=D8327F539A6189C2123F89F2B170EADC; login=true; unick=%E7%94%A8%E6%88%B73109; __SAFETY_CLOSE_TIME__24047327=1; sensorsdata2015session=%7B%7D; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2224047327%22%2C%22first_id%22%3A%2217f7ea105d34c1-087ef7f3a3bbec-977173c-2073600-17f7ea105d4d5b%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24os%22%3A%22Windows%22%2C%22%24browser%22%3A%22Chrome%22%2C%22%24browser_version%22%3A%2299.0.4844.51%22%2C%22lagou_company_id%22%3A%22%22%7D%2C%22%24device_id%22%3A%2217f7ea105d34c1-087ef7f3a3bbec-977173c-2073600-17f7ea105d4d5b%22%7D; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1647333501; SEARCH_ID=05344f68061c476ea546377ac0563232; LGRID=20220315164348-7553573f-0e4d-4a0e-a1cc-d63cbd50d2f7; X_HTTP_TOKEN=dbf713b0116db3ca8283337461a6ef4a1a8eafd163'
        }
    datas = {
        'first':  'true',
        'pn': page,
        'kd': 'java工程师'
    }
    res=requests.post(url=url,headers=headers,data=datas,timeout=4)
    return res.json()['content']['positionResult']['result']

def yanzheng(salary,list):
    flag=True
    for item in list:
        if salary==item.getSalary():
            flag=False
            break
    if flag:
        list.append(CityData(salary))

def addCount(salary,list):
    for item in list:
        if salary==item.getSalary():
            item.addCount()
            break


if __name__ == '__main__':

    try:
        i=1
        while True:
            data=getData(i,'北京')
            for item in data:
                yanzheng(item['salary'],list)
                addCount(item['salary'],list)
                print(item['positionName'],item['workYear'], item['salary'], item['companySize'], item['city'],item['companyFullName'])
            i+=1
    except:
        print('结束')


    for x in range(len(list)):
        for y in range(x+1,len(list)):
            tempx = int(re.search('(\d+).*?(\d+).', list[x].getSalary()).group(1))+int(re.search('(\d+).*?(\d+).', list[x].getSalary()).group(2))
            tempy = int(re.search('(\d+).*?(\d+).', list[y].getSalary()).group(1))+int(re.search('(\d+).*?(\d+).', list[y].getSalary()).group(2))
            if tempx/2>tempy/2:
                temp=list[x]
                list[x]=list[y]
                list[y]=temp

    # for item in list:
    #     print(item.getSalary(),item.getCount())

    salaryList=[]
    countList=[]
    for item in list:
        salaryList.append(item.getSalary())
        countList.append(item.getCount())



    bar = Bar()
    bar.add_xaxis(salaryList)
    bar.add_yaxis('北京',countList)
    bar.set_global_opts(xaxis_opts=opts.AxisOpts(name='薪资'),
                        yaxis_opts = opts.AxisOpts(name='招聘公司数量'))
    bar.render("北京.html")

​ 执行代码返回如下:

​ 同时,我们需要对获取的数据进行可视化解析,采用pyecharts,可以达到如下效果

更新内容:

posted @ 2022-03-20 00:16  木殇丶  阅读(295)  评论(1编辑  收藏  举报