xhr请求有两个sessionid_两个爬虫例子

爬一个AJAX加载的网页

目前多数网站都不会将数据直接放在HTML里,而是采用异步加载的方式,原始页面不包含数据,只是一些样式,在页面加载完后,向服务器发送AJAX请求,从其他接口获取数据,处理后在页面上展示。

一些官方的网站数据,有不少是采用这种方式,比较典型的就是外汇交易中心里的一些数据,下面拿每日活跃债券统计这个功能做个例子。

如何看是不是AJAX请求

649f420690dd5a1b09235493adb6eb63.png

这种网站大家一般都见过,在左上角选择需要查询的日期,然后会显示出所需的数据,但是浏览器上地址栏中网址并没有变化。那在选择日期的时候到底发生了什么?可以通过开发者工具来进行分析。Chorme自带开发者工具,Chorme内核的Edge也包含此工具,感觉两个应该是一样的。在打开上面的页面后,按F12,打开开发者工具,就会看到图2的界面。

e00c816f7743840e969837d10e422f20.png

如果是Chorme可能是全英文的,Edge会有中文的显示。开发者工具里,最上面选择网络(官方的ChormeNetwork),然后在下面筛选器的位置选择XHR,因为AJAX的请求类型就是XHR。目前开发者工具中是空的,因为在打开此工具后有任何操作,没有产生请求。

现在回到CFETS的网页上,换一个日期,就会发现开发者工具中多了一项AtbDlyBltn,类型为xhr,这就是点击查询后产生的AJAX请求。

697f31aa5d8c18361a993827e873271d.png

单击这个请求后,查看详细信息,可以看到右边的请求URLhttp://www.chinamoney.com.cn/dqs/rest/dqs-u-bond/AtbDlyBltn,请求方式为POST。在请求标头部分,X-Requested-With: XMLHttpRequest标记了这个请求就是AJAX。最下面的表单数据里有POST的具体数据:lang: cnsearchDate: 2020-09-29。再看右边的预览,这里是从请求获取的数据,其中records部分就是网页中显示的活跃债券的信息。(官方的CHORME是英文的,但顺序都是一样的,英文看一下也都看得明白。)

a4a4ca59228f5bfc5e4588ec65f3ac13.png

4322a9949fe773c9721288b8c6746e5a.png

请求结果的提取

对这部分数据的请求是向http://www.chinamoney.com.cn/dqs/rest/dqs-u-bond/AtbDlyBltnPOST日期和语言,python里的requests就可以完成模拟请求。代码如下。

 1import json
2import requests
3
4
5BASE_URL = 'http://www.chinamoney.com.cn/dqs/rest/dqs-u-bond/AtbDlyBltn'
6date = '2020-09-28'
7post_data = {
8    'lang': 'cn',
9    'searchDate': date,
10}
11
12r = requests.post(BASE_URL, data=post_data)
13records_list = json.loads(r.text)['records']
14
15for record in records_list:
16    for k, v in record.items():
17        print(k, v)

前面就是一些基本的变量,r = requests.post(BASE_URL, data=post_data)发送请求的部分,取回的结果即在r.text中,是标准的json格式,我们所需要的成交数据就在records的部分,所以使用python中的json包,将其转为字典,字典中records的值为一个包含当日前十成交量债券数据的列表,列表中的每一个元素都是一个字典,对应网页中表格的一行。
如果要批量爬取数据,可以用pandas先生成一个包含所有日期的列表,然后逐日重复上面的爬取过程,而数据的存储比较简便的方式就是利用pandas存储到Excel里。具体代码如下。

 1import requests
2import pandas as pd
3import time
4import datetime
5import json
6
7
8BASE_URL = 'http://www.chinamoney.com.cn/dqs/rest/dqs-u-bond/AtbDlyBltn'
9
10
11def genr_date_range(start: datetime.date, end: datetime.date):
12
13    date_range = pd.date_range(start, end).strftime("%Y-%m-%d").to_list()
14    return date_range
15
16
17def session_fetch(start: datetime.date, end: datetime.date):
18
19    date_range = genr_date_range(start, end)  # 生成日期列表,格式为YYYY-MM-DD
20
21    s = requests.Session()
22    records_list_to_df = list()
23
24    for date in date_range:
25        print(date)
26        post_data = {
27            'lang': 'cn',
28            'searchDate': date,
29        }
30
31        r = s.post(BASE_URL, data=post_data)
32        records_list = json.loads(r.text)['records']
33
34        if len(records_list) == 0:
35            continue
36
37        for record in records_list:
38            record['date'] = date
39        records_list_to_df += records_list
40        time.sleep(3)
41
42    result_df.to_excel('活跃券成交.xlsx')
43
44
45if __name__ == '__main__':
46    start_date = datetime.date(2018, 1, 1)
47    end_date = datetime.date(2020, 9, 30)
48    session_fetch(start_date, end_date)

加入time.sleep(3)的目的是为了防止访问过快被封IP,具体怎么个屏蔽规则我也不敢试,反正在用另一种方法爬这个页面的时候把公司的IP弄屏蔽了,同事也都看不了这个页面了,好在一天之后就恢复了。另一种方式最后会介绍。

另一个例子:爬中金所国债期货持仓数据

cabc75e3e7a6af3f6006d8e98b7c27e8.png

打开中金所的国债期货成交排名,一看这个页面就和CFETS的很像,打开网页源代码,搜索一下永安,果然也是没有,按照上面的操作看一下请求,果然也是AJAX的情况。

ba43dca5cc3a81454b50d83a4a8531cb.png

但是和CFETS不同的是,中金所的网站是请求方式是GET,而CFETS的是POST,还有就是在具体请求的URL里最后还包含了一个id=,后面会有一个数字,换了不同日期后,这个数字会改变,再换回原来的日期,还是会产生一个不同的数字,因此是一个与日期没有对应关系的随机数。但是不要紧,经过测试,随便写个数字应该就行。。。

3315eae8b93619ffd485feaf88a64c6a.png

具体的代码如下。

 1import requests
2import pandas as pd
3from xml.dom.minidom import parse
4import xml.dom.minidom
5
6
7BASE_URL = 'http://www.cffex.com.cn/sj/ccpm/{}/{}/T.xml?id=50'
8date = '20200819'
9
10header = {
11    'Host': 'www.cffex.com.cn',
12    'Referer': 'http://www.cffex.com.cn/ccpm/',
13    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.63',
14    'X-Requested-With': 'XMLHttpRequest',
15}
16
17r = requests.get(BASE_URL.format(date[:6], date[6:]), headers=header)
18
19DOMTree = xml.dom.minidom.parseString(r.text)
20collection = DOMTree.documentElement
21records = collection.getElementsByTagName('data')
22
23tags = ['instrumentid', 'tradingday', 'datatypeid', 'rank', 'shortname', 'volume', 'varvolume', 'partyid', 'productid']
24
25result_df = pd.DataFrame()
26result_list = list()
27for record in records:
28    record_dict = dict()
29    for tag in tags:
30        record_dict[tag] = record.getElementsByTagName(tag)[0].childNodes[0].data
31    result_list.append(record_dict)
32
33result_df = result_df.append(result_list, ignore_index=True)
34result_df.to_excel('cffex.xlsx')

首先,和之前不一样的是BASE_URL,里面多了两个{}。我们再看两个请求的URL,下面两个图一个是请求2020年8月18日的T合约,一个是请求2020年9月10日的T合约,可以看到两个括号位置分别对应年份+月份和日期。将BASE_URL写成这种形式方便之后在批量请求时利用format来补充相关日期信息。

ff1582e8ad6bd1507b9373a0090c8b07.png

f0d70dabeb57a5a3062d58979b8ee579.png

接下来就是header字典,这部分是请求头,与开发者工具中下图部分对应。

8998cbf5e6cb7ae06d63beb1252b21d6.png

再下面就是请求,这里的用requests.get替代了之前的requests.post,因为中金所的网站的请求方式是GETBASE_URL.format(date[:6], date[6:])就是把日期分成两个部分,分别填到{}的位置,形成一个与日期对应的URL,而第二个参数headers=header,是将请求头信息加入到请求中,其实在这个例子里并没有实际的作用,加不加都能获取数据,其他的网站可能会验证请求头,如果确实一些必要的信息,例如User-AgentRefererCookies等,则会限制访问。在之后就是数据处理的过程,与请求数据无关,因为中金所返回的数据不是json而是xml,需要利用xml模块进行解析,然后转换成字典,写入DataFrame后保存。具体批量爬取的代码就不放了,思路和上面是一样的。这是爬取T合约的方法,要是爬取TF和TS,需要调整URL。

另一个被限制了的方法

这个方法是最开始不会上面方法时候用到的,简单粗暴,中金所似乎没有限制,但是外汇交易中心应该是限制了的,就是利用页面自带的导出功能。
中金所持仓数据下面有个Excel附件,链接地址是http://www.cffex.com.cn/sj/ccpm/202009/30/T_1.csv,链接也是一样的规律,日期分成了两个部分,用requests.get是可以下载下来的,然后将这些下载下来的csv文件用pandas等再处理一下,也可以得到数据。在get中是否需要headers,具体需要包含什么,我也没有具体试。而CFETS导出到excel后链接地址是http://www.chinamoney.com.cn/dqs/rest/dqs-u-bond/AtbDlyBltnExcel?lang=cn&searchDate=2020-09-30,地址的规律也都可以看出来,也可以下载下来,但是下了几个后,我就被屏蔽了,不知道是不是因为太快了,之前没有加入sleep

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值