Python爬虫遇到YunSuoAutoJump跳转网页

目录
  1. 前情提要
  2. 过程
    1. 一、给出Location
    2. 二、传递security_id
    3. 三、获取security_mid_id
    4. 四、获取真正目标html
  3. 简化
    1. Location上的简化
  4. 预告

​ 最近在搞一个自制的参考文献归档,查阅记录的工具。需要刚好需要用到Python爬虫,爬取Paper和References。国内由于谷歌学术无法访问,所以怕一个国内的网站,但基本就是一个国内的代理服务器,文献是结果一样的。不过在爬取过程过遇到了网址跳转的问题。

前情提要

​ 在使用requests库爬取关键词时,返回来的并不是用浏览器获得的结果。

​ 例如我们一般爬取搜索页面,输入参数seismic,通过Fiddler抓包发现网址是

http://so.hiqq.com.cn/scholar_complete.php?q=seismic&hl=zh-CN&as_sdt=0%2C5&btnG=

但是我们调用Requests库去Get请求,返回的不是想要的内容,而是

HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Thu, 13 Feb 2020 13:54:15 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Location: https://zz.glgoo.top/scholar?hl=zh-CN&as_sdt=0%2C5&q=seismic&btnG=

响应报文里没有响应体,头文件里就是一个类似重定向的东西,告诉我们,去这个Location找。这个倒是不难,直接再Request这个Location

过程

结果几次的摸索,算是搞清楚了整个过程,我以最一般的情况来说(不带有任何Cookies)。

一、给出Location

猜测是这个代理服务器存在很多个,域名基本都是

xxx..glgoo.top/scholar

xxx.gufenxueshu.com/scholar

每次都需要在kuaisou里给你一个门的钥匙。我们直接将此次Location的变量传给下一个Request

二、传递security_id

对xxx.fufenxueshu.com/scholar的访问,首先会检测有没有Cookies,主要有4个参数

UM_distinctid

_gads

security_session_verify

security_session_mid_verify

前两个浏览器里可以直接获取,后两个,如果没有携带,则会分两次传递过来。本次Request获得了security_id,通过定义一个函数来获取参数并传递给下一个请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def getssv(self,str):
strurl = self.geturl(0,str)
headers={
'Referer': 'http://so.hiqq.com.cn',
'Accept-Language': 'zh-CN,zh;q=0.9',
# "Accept-Language": "zh-Hans-CN,zh-Hans;q=0.8,ja;q=0.6,en-US;q=0.4,en;q=0.2",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
"Host": "xs.gufenxueshu.com",
"Connection": "keep-alive",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-Mode": "navigate"
}
r1 = requests.get(strurl,headers = headers,verify=False)
ssv = r1.headers['Set-Cookie']
ssv = re.findall(r'security_session_verify=''.{32}',ssv)[0]
#print(ssv)
return ssv

三、获取security_mid_id

​ 原理同上,不过这次请求需要带上上次给的ssv,同时,访问的站点后缀发生了一些变化。由于上次传来的响应体还包含了一个YunSuoAutoJump

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, post-check=0, pre-check=0"/><meta http-equiv="Connection" content="Close"/>
<script type="text/javascript">
function stringToHex(str){
var val="";
for(var i = 0; i < str.length; i++){
if(val == "")
val = str.charCodeAt(i).toString(16);
else
val += str.charCodeAt(i).toString(16);
}
return val;
}
function YunSuoAutoJump(){
var width =screen.width;
var height=screen.height;
var screendate = width + "," + height;
var curlocation = window.location.href;
if(-1 == curlocation.indexOf("security_verify_"))
{
document.cookie="srcurl=" + stringToHex(window.location.href) + ";path=/;";
}
self.location = "/scholar?hl=zh-CN&as_sdt=0,5&q=seismic&btnG=&oq=seismic&security_verify_data=" + stringToHex(screendate);
}</script>
<script>setTimeout("YunSuoAutoJump()", 50);</script></head><!--2020-01-30 13:27:50--></html>

​ 分析不难发现,其实就是获取屏幕的分辨率(除去下方的任务栏),例如‘(1920,1080)’再通过一个函数,转化为十进制,我们写一个这样的转化函数。

1
2
3
4
5
6
def stringToHex(self,string):
length = len(string)
hex_string = str()
for i in range(length):
hex_string += hex(ord(string[i]))[2:]
return hex_string

​ 后面只需要在原来的url后面加上

&security_verify_data=stringToHex(1920,1080)

就可以获得ssmv了。

四、获取真正目标html

​ 在拿到两个认证Id后,添加到Cookies里,再回过头来访问原始url就可以正常拿到想要的html了。

简化

## 认证上的简化

​ 其实在后续的请求中,发现有时候不需要ssv和ssmv也可以拿到完整的html,为了保持程序的完整性和速度,我们加一个判断就可以了,如果获取的ssv为空,就直接把这个request丢到beautifulsoup里,不用再去获取ssv和ssmv了。

Location上的简化

​ 另外,其实在第一步获取Location时也可以省略,直接拿一个固定的服务器,不过这样的结果就是,如果这个服务器访问量太大,需要你刷新一下或者排队,也就是再次request一次。两种方法无非就是

  • 固定花费一定时间来到一个通畅的道路
  • 不花费时间来到一个固定的道路,不过这个道路可能会堵塞

预告

​ 其实本次爬虫主要是为了一个自制的文献管理和记录的工具,后续我们会继续在PyQt中使用到这个类,完成我们对Paper和References的获取与记录。