爬虫Part3——Requests进阶

[TOC]

Requests进阶概述

HTTP协议中的请求头header,⼀般会包含安全验证信息,比如常见的User-Agent, token, cookie等。

  1. 模拟浏览器登录 -> 处理cookie
  2. 防盗链处理 -> 抓取梨视频数据
  3. 代理 -> 防⽌被封IP

模拟浏览器登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests

# 初始化session
session = requests.session()
# 准备帐密
data = {
"loginName": "loginName",
"password": "password"
}
# 必须先登录,才能使session获得cookie
url = "https://passport.17k.com/ck/user/login"
resp_login = session.post(url=url, data=data)
print(resp_login.text)
print(resp_login.cookies)
# 使用包含cookie的session拿到书架数据
resp_book = session.get("https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919")
print(resp_book.json())

# 在header中添加cookie进行请求是等效的
resp_req = requests.get("https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919", headers={
"Cookie": "cookie"
})
print(resp_req.json())
  • 使用错误的帐密登录,以抓取login信息

image-20210603110845823

防盗链处理

  • 虽然在开发者工具中能看到
  • 服务器返回页面源代码之后生成以下右边的文件,之后的操作与页面源代码就没有关系了。
  • 浏览器的视图界面是由右边的文件实时渲染的。当删除右边的语句时,左边的相应组件也会同步消失。

image-20210603125745611

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests

# 视频原网站
url = "https://www.pearvideo.com/video_1713901"
contId = url.split("_")[1] # 截取id
videoStatus_url = f"https://www.pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.8770894467476524"

headers = {
"User-Agent": "User-Agent",
"Referer": url # 防盗链,溯源本次请求由哪个url产生
}

# 修正视频地址
resp = requests.get(url=videoStatus_url, headers=headers)
dic = resp.json()
system_time = dic["systemTime"]
video_url = dic["videoInfo"]["videos"]["srcUrl"].replace(system_time, f"cont-{contId}")
print(video_url)

# 下载视频
with open(f"{contId}.mp4", mode="wb") as f:
f.write(requests.get(video_url).content)

代理

1
2
3
4
5
6
7
8
9
10
11
import requests

headers = {
"User-Agent": "User-Agent"
}
proxies = {
"https": "115.219.2.82:3256"
}
resp = requests.get("https://www.baidu.com", headers=headers, proxies=proxies)
resp.encoding = "utf-8"
print(resp.text)

网易云音乐评论

image-20210603164018457

  • 使用定位工具可以发现评论在html文件中的位置,但是不要忘了这是经过脚本生成的,并不是通过get使服务器返还的初始的网页源代码。

image-20210603163736597

  • 网易云音乐的网页页面是由多个html拼接而成,因此可以看见有框架源代码网页源代码两个html文件。
  • 但是在两个html中搜寻,均没有评论资源。由此可知,评论是通过二次请求得到的。

image-20210603163551436

  • 使用Network抓包工具->筛选XHR二次请求->找到comment资源

image-20210603164605502

  • 继续查看headers信息。可知:
    1. 请求目标的URL:https://music.163.com/weapi/comment/resource/comments/get
    2. csrf_token=后为登录信息,?后的参数可以忽略
    3. Request Method: POST请求方式为POST
    4. 同时发送了两个加密data:paramsencSecKey

image-20210603170549795

  • 查看发起请求之前所调用过的栈、js脚本执行的过程。最开始执行的在最底部。点击最后调用的脚本。

image-20210603171043357

  • 现在是压缩过后的代码,需要点击正下方的按钮,更换成优质打印。

image-20210603171817947

  • 在语句send()处设置断点,刷新网页
  • 观察变量request->url,恢复程序执行直到更新为https://music.163.com/weapi/comment/resource/comments/get
  • 数据处于加密状态,因此需要通过调用堆栈不断回调函数,直到找到未加密的data

image-20210603173446525

  • 回调时发现data未加密,立刻定位到加密函数为t8l.be8W
  • 数据在变量i8a与变量e8e之间完成了加密

image-20210603174358762

  • 需要在已定的小范围内进一步缩小范围,因此在函数开始处增加新断点,重新刷新页面
  • 发现在window.asrsea()方法中i8a作为参数之一,返回变量bMl1x
  • 发现变量bMl1x已经被加密,拥有encSecKeyencText
  • bMl1x的数据又赋给e8e.data,由此加密data完成

简易实现版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

api = "https://music.163.com/api/comment/resource/comments/get"
data = {
"cursor": "-1",
"offset": "0",
"orderType": "1",
"pageNo": "1",
"pageSize": "20",
"rid": "R_SO_4_1841819403",
"threadId": "R_SO_4_1841819403"
}

resp = requests.get(api, params=data)
json = resp.json()
print(resp.json())