赞
踩
网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。Python语言,就可以作为爬虫算法的编写语言。
对于非软件专业开发人员来说,网络爬虫技术还是比较复杂的。对于专业B/S结构软件开发人员,网络爬虫软件开发技术是围绕Http协议展开的,主要涉及到知识点有URL、Http请求与Webservice、数据格式。
对于非软件专业开发人员来说,一般合法获取动态数据,可以简单的理解为机器人自动通过浏览器查询网页,自动记录获取的数据,也就是如下图所示发请求(Request)及返回(Respone)过程,和分析网页记录数据过程。
Http网络处理过程简化描述是以下步骤:
客户端(例如浏览器Chrome、自己开发的Python的程序)通过URL发http请求,服务端响应请求,返回HTML+CSS+JavaScipt代码(含数据),而JavaScipt代码中可能含有URL请求,动态的再请求,直到加载完成整个网页。
我们常说爬虫其实就是在这一堆的动态HTTP请求中,找到能给我们返回需要数据的URL链接,无论是网页链接还是App抓包得到的API链接,我们获取后,模拟客户端发送一个请求包,得到一个返回包,我们再针对返回包解析数据。主要内容有:
http请求由请求行,消息报头,请求正文三部分构成。
请求方法 | 说明 |
---|---|
GET | 请求获取Request-URI所标识的资源 |
POST | 在Request-URI所标识的资源后附加新的数据 |
HEAD | 请求获取由Request-URI所标识的资源的响应消息报头 |
PUT | 请求服务器存储一个资源,并用Request-URI作为其标识 |
DELETE | 请求服务器删除Request-URI所标识的资源 |
TRACE | 请求服务器回送收到的请求信息,主要用于测试或诊断 |
CONNECT | 保留将来使用 |
OPTIONS | 请求查询服务器的性能,或者查询与资源相关的选项和需求 |
HTTP响应也由三部分组成,包括状态行,消息报头,响应正文。
我们关心的是响应正文,直接截取我们需要的数据。当然,常用的方法是解析响应的页面,很多时候更完整。
http请求返回格式就是http响应,有固定格式,但是数据体可能多种多样。常用有四种方式:
我们偶尔需要获取互联网上某些数据,例如需要最近今年成品油零售价格数据。
全国油价数据中心(http://data.eastmoney.com/cjsj/oil_default.html)。
Fiddler是一种常见的抓包分析软件,我们可以利用Fiddler详细的对HTTP请求进行分析,并模拟对应的HTTP请求。
使用Fiddler时,本地终端浏览器和服务器之间所有的Request,Response都将经过Fiddler,由Fiddler进行转发。由于所有的数据都会经过Fiddler,所以Fiddler能够截获这些数据没实现网络数据抓包。如下图为Fiddler抓取网络链接请求情况。
跟踪、分析网络请求,发现如下链接是获取数据的接口:
通过跟踪监控请求,在WebForms请求表单中,找到日期数据,也就是接口API的变量。
感兴趣,可以自己再找下日期变量列表的API。
分析网页太麻烦了,直接截取数据方式分析爬取结果。
数据格式:
jQuery11230774292942777187_1622422491627(
{"version":"cafaf0743a45b7965a243c937f23dea5",
"result":{"pages":1,"data":[
{"DIM_ID":"EMI01641328","DIM_DATE":"2021/2/1","V_0":5.8,"V_92":6.13,"V_95":6.59,"V_89":5.74,"CITYNAME":"安徽","ZDE_0":0.06,"ZDE_92":0.06,"ZDE_95":0.06,"ZDE_89":0.06,"QE_0":5.74,"QE_92":6.07,"QE_95":6.53,"QE_89":5.68},
{"DIM_ID":"EMI01521389","DIM_DATE":"2021/2/1","V_0":5.81,"V_92":6.16,"V_95":6.56,"V_89":5.76,"CITYNAME":"北京","ZDE_0":0.06,"ZDE_92":0.06,"ZDE_95":0.07,"ZDE_89":0.05,"QE_0":5.75,"QE_92":6.1,"QE_95":6.49,"QE_89":5.71},
{"DIM_ID":"EMI01641332","DIM_DATE":"2021/2/1","V_0":5.77,"V_92":6.14,"V_95":6.55,"V_89":5.71,"CITYNAME":"福建","ZDE_0":0.06,"ZDE_92":0.06,"ZDE_95":0.06,"ZDE_89":0.05,"QE_0":5.71,"QE_92":6.08,"QE_95":6.49,"QE_89":5.66}
],"count":25},"success":true,"message":"ok","code":0}
);
本案例使用了requests模块,需要单独安装,如下所示:
pip install requests
# -*- coding: utf-8 -*- ''' Created on 2021年5月31日 @author: 肖永威 ''' import requests import re import json from datetime import datetime import pandas as pd from time import sleep import random class Crawler(object): def __init__(self): # 东方财富接口 self.url = 'http://datacenter-web.eastmoney.com/api/data/get' # 调价日期接口API self.params_date = 'callback=jQuery112300671446287155848_1622441721838&type=RPTA_WEB_YJ_RQ&sty=ALL&st=dim_date&sr=-1&token=894050c76af8597a853f5b408b759f5d&p=1&ps=5000&source=WEB&_=1622441721839' # 油价接口API self.params_price = 'callback=jQuery11230774292942777187_1622422491627&type=RPTA_WEB_YJ_JH&sty=ALL&filter=(dim_date%3D%27$date$%27)&st=cityname&sr=1&token=8&p=1&ps=100&source=WEB&_=1622422491638' # 取调价时间 def getDates(self,start_date): dates_json = self._getResponse(self.params_date) self.dates = [] start_date = datetime.strptime(start_date, "%Y-%m-%d").date() for dates in dates_json: dim_date = dates['dim_date'] dim_date = dim_date.replace('/','-') if datetime.strptime(dim_date, "%Y-%m-%d").date() >= start_date: self.dates.append(dim_date) print (self.dates) # 取价格 def getOilprice(self): self.pricedatas = [] k = len(self.dates) i = 0 for dates in self.dates: params_price = self.params_price.replace('$date$', dates) prices_json = self._getResponse(params_price) self.pricedatas.extend(prices_json) sleep(random.randint(0,3)) i = i + 1 print('完成:{:.2%}'.format(i/k)) self.df = pd.DataFrame(self.pricedatas) #self.df.to_csv('price20210531.csv',encoding='utf_8_sig') print(self.pricedatas) # 取API返回值 def _getResponse(self,params): r = requests.get(self.url,params) # 正则表达式,获取括号里的JSON数据 p = re.compile(r'[(](.*?)[)]', re.S) jsondata = re.findall(p,r.text) # 返回数据为Json格式 result = json.loads(jsondata[0]) return result['result']['data'] def main(): Oil_prices = Crawler() tmp = Oil_prices.getDates('2008-03-01') Oil_prices.getOilprice() if __name__ == '__main__': main()
由于是直接截取API返回数据,处理起来相对简单些,直接使用正则方式,匹配出内嵌JSON数据。
其中,代码片段:
r = requests.get(self.url,params)
# 正则表达式,获取括号里的JSON数据
p = re.compile(r'[(](.*?)[)]', re.S)
jsondata = re.findall(p,r.text)
# 返回数据为Json格式
result = json.loads(jsondata[0])
return result['result']['data']
关于爬虫技术,如果仅仅是提高获取数据速度和方便性,实际上也是比较简单的,从IT软件视角来看,都是很成熟的技术和协议,如果你会JSP、前后端分离开发、SOA技术,合法的爬虫将会很简单。重点是找到请求的URL,识别接口API和参数变量。
推荐多了解Webservice接口技术,提高解析数据效率。
参考:
《python爬虫之requests的使用》 博客园 , lweiser ,2019年6月
《深入理解HTTP协议》 知乎 ,零壹技术栈,2018年9月
《通过fiddler抓取HTTP协议的数据包 | 详细介绍fiddler使用过程。西边人西说测试》 CSDN博客 ,西边人细说测试 ,2018年3月
《Fiddler抓HTTP和HTTPS(手机/电脑)数据包步骤》 CSDN博客 ,梦想成为大佬的菜鸟 ,2019年11月
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。