因工作需要,要统计一些使用400客服电话的企业名单,百度的号码验证平台提供了一个查询的能力,对于已经收录的400电话,可以查询到对应的企业名称,但是直接request会遇到 ① url形式爬取到全是JS代码;② 使用post方法返回403 的两个问题。
解决过程1、解决爬取到的全是JS代码的问题
问题:直接从url出手取到的全是JS代码
从截图可以看出,每次查询,顶部url中的search参数会切换为对应的搜索关键词,如 在输入框中输入“4008208820”,那么会url会变成:号码认证平台.
因此第一反应是,直接用get方法,每次切换电话号码时,修改对应的url参数。
# 切换电话号码时,修改对应的url参数 import requests as re # 省略headers的配置环节 for each_number in range(起始号码,结束号码): response = re.get(url + str(each_number)) print(response.text)
结果意料之中,全是JS代码,意味着这条路走不通。
不过看到JS代码,我们应该想到,下方查询的结果肯定是从某个接口请求到的,我们如果能找到对应的api接口,并且构造以假乱真的请求,也许能从接口中拿到数据。
通过分析执行查询时检查模式下network变化找到数据请求的接口api
说干咱就干。
在浏览器中F12进入检查模式,切换到network tab,勾选上“Fetch/XHR”tab。
随便输入一个电话号码,点击搜索。可以看到 一瞬间出现了2个网络请求的过程。
通过分析两个请求的内容,我们可以发现:
-
abdr这个请求,主要是向 https://miao.baidu.com/abdr 这个接口请求,request的参数为一个字符串,返回的数据包含 data、sign、key_id
-
search这个请求,向 https://haoma.baidu.com/api/v1/search 这个接口请求,参数是一个由data、sign、page、key_id、size和serach参数构成的字典。其中data、sign和key_id参数和刚刚abdr返回的数据是一样的!而通过手动构造几个新的搜索可以发现,page和size两个个参数在不同的查询中是不变的!而search参数正是我们输入的电话号码!而这个接口返回的数据中,刚好包含了对应的企业名称。Perfect。
至此,我们可以梳理整个链路了:
- 请求abdr接口,拿回来 data、sign、key_id参数;
- 将data、sign、key_id三个参数和不变的size、page,以及我们输入的搜索词(search参数) 构造成request的data,请求search接口;
- 解析search接口的返回值,即可拿到电话对应的企业名称。
编码实现:
for each_number in range(起始号码,结束号码): # 首先 请求abdr接口 # 此处省略构造 headers 和 data的步骤 abdr_response = re.post(url = "https://miao.baidu.com/abdr", headers = abdr_headers, data = abdr_data) # 然后请求search接口 # 此处省略构造 headers的步骤 search_data = { "data": abdr_response.data, "sign":abdr_response.sign, "key_id":abdr_response.key_id, "page":1, "size":10, "search":str(each_number) } search_response = re.post(url = "https://haoma.baidu.com/api/v1/search", headers = search_headers, data = search_data)
然而,解析此处的search_reponse却是403。
解决通过接口POST请求,返回403错误的问题当看到接口返回403,也就是服务器禁止访问的时候,第一时间感觉应该是cookie的问题,cookie设置错误是最有可能导致服务器禁止访问的。
因为我这里是直接将手动搜索时abdr的cookie配置到本次abdr的headers中,将手动搜索时search的cookie配置到本次search的headers中,一些情况下这个使用是没问题的,这里可能是存在一些动态的调整导致前一次的cookie中的某些参数在最新的一次请求中没法使用了。
为了排查cookie的问题,我们再手动搜索一次,对比两次search请求的cookie,我们可以发现,cookie中的其他参数一模一样,但是 ab_sr这个参数的值不一样了!
问题可能就出在这里,但是这个新的参数从哪儿来的呢?联想到data、key_id、sign这些参数来自于adbr请求,我们再回过头去研究一下adbr请求。
可以看到,adbr请求其实返回了一个cookie,而这个cookie中的ab_sr参数正是新的search参数中的ab_sr参数。不过这个返回的cookie并不在显式的返回结果中,而是要用response.cookie才能取到,所以被忽略了。
到这里差不多已经解决问题啦,我们根据abdr的返回的cookie中的ab_sr参数来更新新的search请求的cookie中的ab_sr参数,即可实现请求。
for each_number in range(起始号码,结束号码): # 首先 请求abdr接口 # 此处省略构造 headers 和 data的步骤 abdr_response = re.post(url = "https://miao.baidu.com/abdr", headers = abdr_headers, data = abdr_data) # 然后请求search接口 # 此处省略构造 headers的步骤 search_data = { "data": abdr_response.data, "sign":abdr_response.sign, "key_id":abdr_response.key_id, "page":1, "size":10, "search":str(each_number) } # 根据abdr接口返回的cookie更新search_headers,主要是ab_sr参数 search_response = re.post(url = "https://haoma.baidu.com/api/v1/search", headers = search_headers, data = search_data)
这次返回了正常的数据,大功告成!
总结-
在构建爬虫时,充分利用检查模式,分析接口调用情况是很重要的意识。
-
遇到403错误时,重点分析cookie的问题(用户凭证,比如百度的BAIDUID也是通过cookie传递给接口的)
-
要对比同一接口在不同调用下的参数、cookie、response的的细微差异,往往能找到有价值的线索
-
一次查询、传输涉及到多个接口时,要梳理接口之间的数据传输关系,一个接口如果没有价值,肯定不会被调用嘛,所以存在的几个接口肯定都是有用的。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)