Ciallo~(∠・ω< )⌒★
Python爬虫学习笔记
一、涉及到的库
-
HTTP请求库requests
-
pip install requests
-
-
HTML解析器beautifulsoup
-
pip install beautifulsoup4
-
二、爬虫的架构
一个python爬虫主要由五个部分组成:
- 爬虫调度器
- 负责统筹协调其他四个模块的协调工作
- URL管理器
- 管理URL链接,维持已经爬取的URL集合和未爬取的URL集合,提供新的URL链接接口
- 其主要功能包括维护URL队列(如对已爬取和未爬取的URL进行分类)、去重处理、优先级管理等
- HTML下载器
- 用于从URL管理器中获取未爬虫的URL链接并下载HTML网页
- HTML解析器
- 从HTML下载器中获取已经下载的HTML网页,并从中解析出所需要的数据
- 数据存储器
- 用于将HTML解析器解析出来的数据通过文件或者数据库形式储存起来
三、HTTP请求库requests
1.简介
requests是python中进行网络请求的一个常用的第三方库,他是基于python内置的HTTP请求库urllib而编写的,他对urllib进行了封装,使得python发送HTTP请求更加简便。
通过pip install requests
即可安装该库,通过import requests
即可导入到文件中。
2.基本使用
发送请求
在使用requests发送请求时,我们常使用requests.get/post(url,params,args)
方法来发送get/post请求,其常用的参数如下:
-
url
- 要访问的目标网页URL
- 可以在浏览器头找到
- 如:https://www.baidu.com/
-
params
-
访问目标URL所带的参数,为字典格式,在发送get请求时会自动将其拼接到URL后面
-
如:
-
import requests url="https://www.baidu.com/"#访问的URL params={'wd':'原神'}#参数 rq=requests.get(url=url,params=params)#发送请求 print(rq.url)#输出实际访问的网址 #注requests.get()方法最后会返回一个Response对象,其有一个属性为url,即本次实际请求的URL
-
#其结果应该如下 https://www.baidu.com/?wd=%E5%8E%9F%E7%A5%9E
-
注:URL中可以包含中文,但是中文需要进行特殊编码才可以在网上传输,在我们发送请求时可以自动进行编码,如果我们需要解码,可以查看下面的网站
-
-
data
- post请求的请求体,一般用POST方法提交数据,也为字典形式
-
headers
- 请求头,为字典格式
- 请求头是在HTTP协议中用于传递关于请求的额外信息的部分。它包含了客户端(通常是浏览器或应用程序)与服务器之间进行通信所需的元数据。
- 其常用的字段如下
- User-Agent
- 用于标识发出请求的客户端应用程序、操作系统、硬件平台、浏览器和其他相关信息
- 即服务器用来确认你的设备的
- Referer
- 指示了当前请求是从哪个URL页面发起的,可以帮助服务器识别请求的来源,服务器常用他来识别你是不是走正规路子过来的
- Cookie
- 包含来自客户端的Cookie信息
- 比如有些网站会对你的身份进行验证,在访问时需要你登录留下的Cookie才能访问
- User-Agent
- 获取方法
- 浏览器->右键->检查->网络
-
timeout
- 超时时间
- 有些时候,我们访问的服务器难以连接或者繁忙,长时间未收到答复,这时候我们的爬虫便会卡死在这里,通过设置timeout可以在到达规定时间就停止对该URL的访问
-
verify
- 是否验证服务器的TLS证书
- 可以接受一个布尔值,表示是否验证
- 也可以接受一个路径字符串,来使用本地的特定的CA证书对服务器身份进行验证
- TLS(Transport Layer Security)证书是一种用于确保互联网通信安全的数字证书。它通过加密数据传输来保护用户隐私,并通过验证服务器身份来防止中间人攻击。
- 是否验证服务器的TLS证书
-
allow_redirects
- 是否让requests做重定向处理,接受一个布尔值,默认为True
-
cookies
- 附带的本地的cookie数据
- 该参数也可以写在头文件里
响应对象
当我们使用requests发送请求后,requests会将请求结果封装为一个Response对象,该对象有如下属性
- status_code
- 状态码,如果等于200表示请求成功
- 如果不等于200可以搜索对应的状态码,推断失败的缘由
- ps:403试试在header里添加Referer
- 状态码,如果等于200表示请求成功
- encoding
- 字符编码,requests会根据headers推测编码,如果推测不到会默认指定ISO-8859-1为编码集
- 我们可以通过查看返回的HTML文件的头部区域,编码通常会放在头部区域的meta标签中
- 如果我们发现encoding的值并不是HTML实际使用的编码集,此时我们可以修改encoding属性,使得字符可以正确显示
- 字符编码,requests会根据headers推测编码,如果推测不到会默认指定ISO-8859-1为编码集
- text
- 网页的字符串格式内容
- 即将我们得到的html文件变为字符串
- content
- 以字节形式返回的内容,通常用于视频、图片等
- headers
- 查看使用的请求头
- url
- 查看实际访问的url
- cookies
- 访问网站使用的cookie
3.实例-访问百度网页
#导入HTTP请求库requests
import requests
#百度搜索的URL
url="https://www.baidu.com/"
#请求头
header={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0'
}
#向百度搜索发送请求,时间限制为5s
response=requests.get(url=url,headers=header,timeout=5)
print(f"返回值类型为:{type(response)}")
print(f"响应状态码为:{response.status_code}")
print(f"字符集为:{response.encoding}")
print(response.text)
四、URL管理器
1.作用
对URL进行管理,防止重复和循环爬取,支持新增URL和取出URL,可以进行URL爬取优先级的管理等
2.简单实现
本次我们可以简单实现一个URL管理器,其主要包含新增URL和取出URL两个对外接口,并确保不会重复爬取一个URL。
class UrlManager():
"""
url管理器
"""
#初始化
def __init__(self):
#未爬取url
self.__new_url=set()
#已爬取url
self.__old_url=set()
#添加一个url
def add_url(self,url):
#判断URL是否合法
if url==None or len(url)==0:
return
#判断是否已经存在该url
if url in self.__new_url or url in self.__old_url:
return
#添加
self.__new_url.add(url)
#添加多个url
def add_urls(self,urls):
#判断urls是否合法
if urls==None or len(urls)==0:
return
for i in urls:
self.add_url(i)
#取出一个url
def get_url(self):
#判断是否有未取出的url
if self.have_new_url():
url=self.__new_url.pop()
self.__old_url.add(url)
return url
return None
#判断是否有未取出的url
def have_new_url(self):
return len(self.__new_url)>0
#返回未爬取的url和已爬取的url的集合
def show_urls(self):
return self.__new_url,self.__old_url
五、正则表达式
1.简介
正则表达式(Regular Expression,简称 regex 或 regexp)是一种用于匹配字符串中字符组合的模式。正则表达式广泛用于搜索、替换、分割字符串等操作。
正则表达式可以通过特定的字符组合来匹配符合某一格式的字符。
Python中内置了正则表达式库re,使用时,我们通过import re
导入即可
正则表达式例子
import re
#原始字符串
strings="我的邮箱是6932145698@bnjf.com"
#定义一个正则表达式对象
compile=re.compile(r'\d*@\w*\.com')
#输出匹配到的字符
print(compile.search(strings)[0])
6932145698@bnjf.com
2.匹配规则
字符 | 功能 |
---|---|
. | 匹配任意一个字符('\n’除外) |
[ ] | 匹配括号内列举的字符 |
\d | 匹配数字0-9 |
\D | 匹配非数字 |
\s | 匹配空白 |
\S | 匹配非空白 |
\w | 匹配单词字符,即0-9、a-z、A-Z、_ |
\W | 匹配非单词字符 |
* | 匹配前一个字符出现0次或无限次 |
+ | 匹配前一个字符出现1次或无限次 |
? | 匹配前一个字符出现1次或0次 |
{m} | 匹配前一个字符出现m次 |
{m,n} | 匹配前一个字符出现m到n次 |
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
| | 匹配左右任意一个表达式 |
(ab) | 将括号中的字符作为一个分组 |
(?P) | 分组起别名,匹配到的子串组在外部是通过定义name来获取的 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
\num | 引用分组num匹配到的字符串 |
3.re模块方法
re.compile(pattern)
- pattern:正则表达式
- 创建一个正则表达式对象(Pattern)
re.match(pattern,string)
- pattern:正则表达式;string:要进行匹配的字符串
- 使用正则表达式pattern对字符串string从头开始进行匹配,返回一个match对象
- match对象.group()即可取出匹配到的字符串
- 若正则表达式内有分组,可以向group传递参数来返回某个分组
re.search(pattern,string)
- pattern:正则表达式;string:要进行匹配的字符串
- 使用正则表达式pattern对字符串string进行匹配,返回第一个匹配到的match对象(可以对任意位置匹配)
re.findall(pattern, string)
- pattern:正则表达式;string:要进行匹配的字符串
- 使用pattern对string进行匹配,将所有匹配到的字符串合成一个列表返回
- 若遇到了分组,会将每一个符合条件的字符串内的分组封装为一个元组
re.finditer(pattern, string)
- 参数与作用都与findall一样,但是返回值为一个迭代器
pattern对象.match(string)
、pattern对象.search(string)
、pattern对象.findall(string)
- 效果同re.match()|search()|findall()一样
re.sub(pattern, repl, string, count=0)
- pattern:正则表达式;repl:要替换的字符串;string:要进行匹配的字符串;count:替换次数
- 将pattern匹配到的字符串以repl做替换,若count指定一个大于0的数,则最多替换count次,若为0,则全部替换
re.split(pattern, string, maxsplit=0)
- pattern:正则表达式;string:要进行匹配的字符串;maxsplit:最大分割次数
- 以pattern匹配到的字符串做分割
4.贪婪匹配和非贪婪匹配
在前面正则表达式匹配规则中讲到了.
匹配任意一个非\n
的字符,而*
匹配前面一个字符0次或无限次,则使用.*
的话就可以匹配到我们任意长度的任意字符,但是,有时候,.*
却不能取得我们想要的结果,如:
import re
#原始字符串
s='hello 1234567 world'
#定义一个正则表达式对象,匹配中间数字(将中间数字作为分组,可以单独拿出)
compile=re.compile(r'.*(\d+).*')
result=compile.match(s)
print(result.group(1))
7
可以,看到,(\d+)
目的是匹配一个无限长的数字字符,但是最终结果却只匹配出了7,当我们将前面的.*
也作为一组时,可以看到.*
结果如下
hello 123456
原因是.*
在(\d+)
前面,.*
会尽可能多的匹配任意字符,但是会给(\d+)
留一个匹配位,所以才会导致(\d+)
只匹配到最后一个数字。此时,.*
这种模式我们称为贪婪匹配,它会尽可能多的匹配符合它的字符。
在前面我们讲到了?
会匹配前面一个字符1次或0次,即?
会极大程度的限制前面字符的匹配,故当.*?
在一起时,会尽可能少的匹配字符,减少对后面字符匹配的影响,此时,.*?
这种模式我们称为非贪婪匹配,它会尽可能少的匹配符合它的字符。
import re
#原始字符串
s='hello 1234567 world'
#定义一个正则表达式对象,匹配中间数字(将中间数字作为分组,可以单独拿出)
compile=re.compile(r'.*?(\d+).*')
result=compile.match(s)
print(result.group(1))
1234567
使用非贪婪匹配模式成功匹配中间数字
实例——提取出百度搜索首页的百度热搜
import requests
import re
#请求URL
url="https://top.baidu.com/board"
#请求头
header={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0',
}
#发起请求
rep=requests.get(url,headers=header,params={'tab':'realtime'})
#状态码
print(f"状态码为:{rep.status_code}")
#实际访问URL
print(f"实际访问的URL为:{rep.url}")
#通过观察,我们可以看到,我们需要的资讯都被一个含有class=c-single-text-ellipsis的div标签包裹
#所以我们可以通过正则表达式匹配含有class=c-single-text-ellipsis的标签
#正则表达式(HTML注释获取时会自动忽略)
reg=re.compile(r'<div class="c-single-text-ellipsis">(.*?)</div> ')
#进行匹配
result=reg.findall(rep.text)
#输出匹配结果
for i in range(len(result)):
print(f"{i}.{result[i]}")
六、网页解析器BeautifulSoup
1.简介
BeautifulSoup
是一个用于解析 HTML 和 XML 文档的 Python 库。他具有处理不同解析器的能力,如 html.parser
、lxml
和 html5lib
。
通过pip install BeautifulSoup4
来安装该库,通过from bs4 import BeautifulSoup
来导入该库、
2.初始化BeautifulSoup对象
在我们使用BeautifulSoup库对HTML文档进行解析之前,我们需要先创建一个BeautifulSoup对象。
soup=BeautifulSoup(markup,features)
-
markup
-
需要解析的HTML文档内容
-
可以直接将requests获取到等等HTML文档传递给他,也可以使用open打开本地的HTML文件
-
#法1 markup=request.get(url="xxx.xxx").text #法2 markup=open("xxx",mode='r')
-
-
features
-
所使用的解析器
-
beautifulsoup可以使用四种解析器,如下
-
解析器 对应字符串 优点 缺点 Python标准解析器 html.parser Python的内置库,执行速度适中,文档容错能力强 旧版本(3.2以前)Python的容错能力差 lxml HTML解析器 lxml 速度快、文档容错能力强 需要安装lxml库,需要安装c语言库 lxml XML解析器 xml 速度快、唯一支持XML的解析器 需要安装lxml库,需要安装C语言库 html5lib html5lib 最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档 需要安装html5lib库,速度慢、不依赖外部扩展
-
3.选择器
1)总览
选择器可以从beautifulsoup对象中提取到我们需要的标签对象。
beautifulsoup对象可以使用三种选择器
- 节点选择器
- 方法选择器
- css选择器
2)节点选择器
对于一个beautifulsoup对象soup,我们可以通过soup.tag
的方式来获取tag标签的bs4.element.Tag对象,当soup对象中有多个对应节点时,只获取第一个节点。
节点选择器可以嵌套使用,如
test.html
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>
这里是span外面
<span>这里是span里面</span>
</h1>
</body>
</html>
test.py
from bs4 import BeautifulSoup
html=open('test.html','r',encoding="utf-8")
soup=BeautifulSoup(html.read(),'lxml')
html.close()
print(soup.h1)
print("#"*30)
print(soup.h1.span)
我们还可以对访问Tag对象的关系属性来找到与其有关系的其他标签
soup.tag.关系 | 作用 | 返回值 |
---|---|---|
子节点 | ||
contents | 获取子节点 | 列表 |
children | 获取子节点 | 迭代器 |
子孙节点 | ||
descendants | 获取子孙节点 | 迭代器 |
父节点 | ||
parent | 获取父节点 | tag对象 |
祖先节点 | ||
parents | 获取祖先节点 | 迭代器 |
兄弟节点 | ||
next_sibling | 获取下一个同级的节点 | tag对象 |
next_siblings | 获取所有的同级的节点 | 迭代器 |
previous_sblings | 获取所有父级节点 | 迭代器 |
previous_sbling | 获取父级节点 | tag对象 |
3)方法选择器
find()
- 作用:在soup对象中查找符合要求的Tag对象
- 参数:name,attrs,recursive ,text ,**kwargs
- name:查找的标签
- 传入单个标签名
- 传入正则表达式对象compile
- 传入参数列表
- attrs:属性值
- 传入一个字典,里面的键表示匹配的标签的属性,值表示对应的属性值
- 值可以是正则表达式对象compile
- recursive
- 是否搜索子节点,默认为True
- string
- 搜索标签内字符串,可以传入字符串,字符串列表,正则表达式对象compile,True
- name:查找的标签
find_all()
- find()的升级版,返回所有匹配到的Tag,会将其打包成一个数组返回
find_parent()
与find_parents()
- find_parent()与find_parents()都可以搜索tag对象的父级元素
- 但是前者只返回搜索到的最接近的一层父级元素
- 后者会由最近的一层向外层搜索,并返回每一层的元素
- 该方法亲测比节点选择器好用
find_next_sliblings()
与find_next_slibling()
- 返回后面的兄弟元素
find_previous_sliblings()
与find_previous_slibling()
- 返回前面的兄弟元素
4)css选择器
通过使用select()
方法,我们可以使用css选择器来选择标签,该选择器用法与css内用法一样
#类选择器
'.className'
#id选择器
'#idName'
#标签选择器
'tagName'
#组合选择器
'css选择器1[属性名=属性值] css选择器2[属性名=属性值] ....'
4.tag对象的一些属性
- name
- 获得标签的名称
- 返回字符串
- attrs
- 获得标签的属性
- 标签的属性会封装成为字典返回
- string
- 获得节点的字符串内容
- 返回字符串
- tag对象[‘属性名’]
- 该种方式也可以获得到指定的属性,返回的是一个列表
实例——从vilipix排行榜上爬取高清图片
import requests
from bs4 import BeautifulSoup
import re
from utils import url_manager
import os
##爬取vilipix的每日排行榜
#初始化URL管理器
urlManager=url_manager.UrlManager()
#请求URL
url="https://www.vilipix.com/ranking"
#请求头
header={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0',
}
params={
'date':'20240528',#日期
'mode':'daily',#类型——每日的排行榜
'p':'1',#页数
}
#图片详情页链接筛选正则表达式
comp=re.compile(r"/illust/\d+")
print("请求排行榜页面")
#发送排行榜页面请求
resp=requests.get(url=url,headers=header,params=params)
#创建BeautifulSoup对象
soup=BeautifulSoup(resp.text,'lxml')
#筛选图片详情页的链接地址
detail_links=soup.find_all(name='a',recursive=True,attrs={'href':comp})
#将详情页URL拼接完整后交给url管理器
urlManager.add_urls(["https://www.vilipix.com"+i['href'] for i in detail_links])
print("请求详情页")
detail_urls=[]
#从url管理器取出URL,对详情页面的图片URL进行爬取
while urlManager.have_new_url():
#取出一个url
new_url=urlManager.get_url()
print(f"访问详情页:{new_url}")
#请求详情页
detail_page=requests.get(url=new_url,headers=header)
#创建BeautifulSoup对象
soup2=BeautifulSoup(detail_page.text,'lxml')
# print(soup2.find_all(name='img'))
#获取含有目标图片的标签
img_url=(soup2.find(name='img',
attrs={
'src':re.compile(r'https://img\.hongyoubizhi\.com/.*')
})
)
detail_urls.append(img_url['src'])
#将图片的url交给url管理器
urlManager.add_urls(detail_urls)
#下载爬取到的图片
#检查文件夹是否存在
if os.path.exists("图片"):
pass
else:
os.makedirs("图片")
#将当前的工作目录切换到“图片”下
os.chdir("图片")
print("正在下载")
i=1
while urlManager.have_new_url():
#输出进度条
print(f"\r已下载{i}/30[{'■'*i}⇒{' '*(30-i)}]",end='')
#向服务器请求图片
img=requests.get(url=urlManager.get_url(),headers=header)
#保存图片
with open(f"{i}.jpg",mode="wb+") as file:
file.write(img.content)
i+=1
print()
print("下载完成")
七、JS渲染问题
1.导引
以上我们所进行的都是对静态网页进行爬取,即我们要爬取的内容都是在html上已经写好了的,但是,有时候我们要爬取的资源并不是一开始就在html上,而是在html加载后由js后续渲染出来的,此时我们使用前面的方法爬取就有可能会无法爬取到我们想要的内容。下面介绍两种解决方案,帮助我们解决这种问题。
2.渲染页面
导引
Python中可以执行JS渲染页面的第三方库有很多,如Selenium、PhantomJS、Pyppeteer、Requests-HTML等,其中Requests-HTML是一个基于我们常用的Requests库的HTML解析库,Requests库的操作基本都可以在该库上方式进行,并且Requests-HTML库可以加载JS代码,故本次使用该库来进行JS渲染。
Requests-HTML安装
命令窗口执行
pip install requests-html
基本使用
发起请求
在Requests-HTML中,我们一般使用HTMLSession来发送请求,故在发送请求之前,我们需要先初始化一下HTMLSession类
from requests_html import HTMLSession#导入HTMLSession类
session=HTMLSession()#初始化HTMLSession
初始化HTMLSession类后,我们可以通过Requests库内发送请求的方式来使用Session对象发送请求和处理响应内容。
from requests_html import HTMLSession
#初始化HTMLSession
session=HTMLSession()
url='https://baidu.com'
header={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
}
resp=session.get(url=url,headers=header,)
print(resp.status_code)
print(resp.url)
而独属于Requests-HTML的则是返回的对象的html属性,访问由Requests-HTML生成的Response对象的html属性时,会返回一个HTML对象,该对象是Requests-HTML的精髓
HTML对象的一些属性与方法
- 属性
- html
- 该属性为html文件内容
- links
- 该属性为html文件中所有的链接组成的列表
- absolute_links
- 该属性为html文件中所有的绝对链接组成的列表
- html
- 方法
- find()
- 传入一个CSS选择器(字符串),可以根据CSS选择器来查找html文件中符合条件的标签,并将他们封装成
Element
对象作为一个列表返回- element对象的一些属性
- text:元素标签包裹的文本内容
- html:元素标签的html内容
- attrs:元素标签属性构成的字典
- 传入一个CSS选择器(字符串),可以根据CSS选择器来查找html文件中符合条件的标签,并将他们封装成
- find()
渲染页面
通过使用html对象的render方法即可对html对象进行渲染
在初次使用时,会自动下载一个chromium(谷歌浏览器内核),之后render方法就会调用chromium来对html页面进行渲染
render方法还可以传递以下参数
- retries
- 如果渲染失败,会尝试重新渲染的次数,默认为8次
- wait
- 每次渲染之前等待加载的次数,默认为0.2s
- scrolldown
- 是否滚动到页面底部,默认为False
- sleep
- 渲染后等待的时间,可以确保页面完全加载,默认为0
- timeout
- 渲染超时时间,默认为8秒
例
豆瓣网电影页面豆瓣电影 (douban.com)
from requests_html import HTMLSession
from pprint import pprint
import requests
#初始化HTMLSession
session=HTMLSession()
url='https://movie.douban.com/'
header={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
}
resp=session.get(url=url,headers=header)
resp.html.render(timeout=8,scrolldown=True,sleep=3)
print(resp.html.html)
3.寻找接口
使用渲染页面的方法几乎能解决大部分的js渲染问题,但是由于其要启动chromium进行渲染,而且渲染需要时间,导致其大规模爬取数据时效率不高。
而寻找接口的方式是直接在数据来源上进行获取,此种方法爬取数据十分迅速,但是其最大的问题就是:接口地址不好找。
寻找接口的方式通常是在浏览器的控制台->网络处。
如:
import requests
import json
##爬取米游社绝区零帖子的评论
#请求URL
url="https://bbs-api.miyoushe.com/post/wapi/getPostReplies"
#请求头
header={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0',
}
#打开文件
file=open("coments.txt",mode="w+",encoding='utf-8')
#从0开始,步长为20,到500结束,即爬取100条评论
for i in range(0,501,20):
#将内存中的数据写入到文件中
file.flush()
params = {
'gids': '8',
'is_hot': 'true',
'last_id': f'{i}', # 该参数控制动态加载评论
'post_id': '53257600',
'size': '20',
}
#发送请求
resp=requests.get(url=url,headers=header,params=params)
#加载对应页的评论JSON数据
datas=json.loads(resp.text)
#['data']['list'][i]['reply']['content']——评论内容
#['data']['list'][i]['user']['uid']——评论用户id
#['data']['list'][i]['user']['nickname']——评论用户名
for j in range(20):
content=datas['data']['list'][j]['reply']['content']
uid=datas['data']['list'][j]['user']['uid']
unick=datas['data']['list'][j]['user']['nickname']
file.writelines(f"用户ID:{uid} 昵称:{unick} 评论内容:{content}\n")