1.爬虫的概念

模拟浏览器,发送请求,获取响应

原则上,只要是浏览器能做的,爬虫都能做

2.爬虫的作用

1.数据采集

2.软件测试

3.12306抢票

4.网站上的投票

5.网络安全

3.爬虫的分类

3.1根据被爬取的网站的数量不同,可分为

31.1通用爬虫

3.1.2聚焦爬虫

3.2根据是否以获取数据为目的,可以分为

3.2.1 功能性爬虫

3.2.2 数据增量爬虫

3.3根据url地址和对应的页面内容是否改变,数据增量爬虫可以分为

3.3.1 基于url地址变换,内容也随之变换的数据增量爬虫

3.3.2 url地址不变,内容也变换的数据增量爬虫

4. 爬虫的流程

url

发送请求,获取响应

解析

5. http协议复习

HTTPS比HTTP更安全,但性能更低

http默认端口80,明文传输

https默认端口443

常见的请求头与响应头

请求头

host 域名

Connection 长连接

Upgrade-Insecure-Requests 升级为https的请求

*User-Agent 用户代理,提供系统信息和浏览器信息

*Referer 页面跳转出处,防盗链(图片/视频)

*Cookie 状态保持

响应头

Set-Cookie

常见的状态码

200:成功

302:跳转

303:重定向POST

307:重定向GET

403:拒绝

404:找不到页面

500:服务器内部错误

503:服务器由于维护或者负载过重未能应答

所有的状态码都不可信,一切以是否从抓包得到数据为准

network中抓包得到的源码才是判断依据,elements中的源码是渲染之后的源码,不能作为判断标准

6.request模块

6.1request模块的作用

发送http请求,获取响应数据

6.2 安装

pip install requests

6.3 发送get请求

import requests
# 目标url
url="https://www.baidu.com"
# 向目标url发送get请求
response=requests.get(url)
# 打印响应内容
print(response.text)
#返回的是str类型

6.4response响应对象

response.text返回的可能是乱码,因为编码原因,自动使用自己推测的编码,可以手动改变用以下代码:

response=requests.get(url)
response.encoding=‘utf8’

也可以使用下列方法进行自定义编码:

#response.content是存储的bytes类型的响应源码,可以进行decode操作,转为正确的str类型
response.content.decode()
#decode默=默认参数为utf-8

response.text和response.content的区别

response.text #类型为str,自行推测的编码
response.content#类型为bytes,需要用decode来转换为str

6.5常见的响应对象参数和方法

response.url #响应url
response.status_code #状态码
response.request.headers #响应对应的请求头
response.headers #响应头
response.cookies #答应响应设置cookie

6.6request模块发送请求

发送带请求头的模块(带上User-Agent)

import requests
# 目标url
url="https://www.baidu.com"
# 创建字典,写上请求头需要包含的内容,该user——agent是从浏览器抓包下来
headers={
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36 Edg/120.0.0.0'
}
#请求,并将字典赋值给headers参数
response1=requests.get(url,headers=headers)

以上方法其实就是伪装成浏览器去请求

7.发送带参数的请求

7.1 url中直接带参数

with open("baidu.html",'wb')as f:
    f.write(response1.content)
#将请求到的内容保存在新的文件里

7.2 使用params参数

7.2.1构建参数字典

7.2.2 发送请求的时候设置参数字典(与请求头设置类似)

url='http://www.baidu.com/s?'
headers={
 'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36 Edg/120.0.0.0'
 }
#构建参数字典
kw={'wd':'python'}
# 将参数传给params
response=requests.get(url,headers=headers,params=kw)
print(response.content.decode())

7.3在headers中携带Cookie

1.从浏览器复制user-agent和cookie

2.浏览器请求头字段和值必须与headers参数中的一致

3.headers请求参数字典中的Cookie键对应的值是字符串

import requests

url='https://github.com/dashboard'

#构建请求头(有cookie和user-agent)
headers={'User-Agent':
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36 Edg/120.0.0.0','Cookie':
'_octo=GH1.1.1235221592.1689322009; _device_id=8525f19d21277cdad23852e7fc76e6a8; preferred_color_mode=light; tz=Asia%2FShanghai; has_recent_activity=1; saved_user_sessions=147335186%3AaxSCC7rbNerhoWRJQRlZJLpGCuObDSRNaGy8x39wnBsypbJu; user_session=axSCC7rbNerhoWRJQRlZJLpGCuObDSRNaGy8x39wnBsypbJu; __Host-user_session_same_site=axSCC7rbNerhoWRJQRlZJLpGCuObDSRNaGy8x39wnBsypbJu; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22auto%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=akdhjss; _gh_sess=yBi7IBMRNgP4yMYJgTf2FlQ4WF1%2BCC%2F2GRxw7ckEm2rr1%2FWiSv3%2BEmZoLpOvmxiex%2F27SfcszIpUKUDEGfBD2s9M1Wyrs%2FltrFvkLLQdGL4chDMM2H0B5fBgqMv%2FaG2gT4UyoDCQ3JjIsmxvDmyJHhsejXAcDAsps9lB7FuAE6xN1RsbMebjjjY5lYHEE%2FGyjDIA2bnsYearI9qV24hcgMn23Xcg7Viztv5nkIvk8Zdq7QunEnqI76XuLM1jVSS9blDU12DKzejwqmggCQwxoTK25Otl5z3Mo6tS5nVKHEN1mkd5jENmcYrQY%2BPmCyVHJnJgxfSl%2FkJQvz%2BZrqt8JQgTpNoNnn%2B8HPA3reWVfsnniQrZxn9DIpiwMHwh0CRS2f2UsDrSBF%2Bx3qrzr6cI%2Bpzm3nz86LuHvlsV8rnelhO4CcbDMP%2BqcfOUIbxiXH31v3MfqmRo9qi2QOMPPsEgUum6t4d%2FF%2FdfjrTtTTdj65xmx2yk0EMNi%2Fk2SMMXuNwlTQGse2Po9fpOmxUfxjslqynUXWyzDeII2lRSSIUdVunFxUqwugvkA0981zqN1rPSAPNVyJoU3FdPVPVw6Y5pSWPHHbYXK1%2Fk%2BC58NBqgNB9wRjZLTlv3aoFnhg4b2vF2IfeqwjE3IIxeE8s5lZgRqYKrzxqN1ZLllPw9yPUWOG%2BySnv0Rncj5FqDsGzwbVpD2yKZhIJM6Bw%2BILGgPWJHBZpIwJ0B%2BGQRmf3%2BxGoJyCWcIr6%2FI%2Bw6937HIUTGO7ppsvCfqum1dbqfNcWVdASbcRct16qGaMYiU1K6r49yGhZB4pXHUkLMSSEPa9qW5GfaQsqeJLyP0TTvgk7j--8TkhBAxrKqmF5sPy--G%2FpHF6X3KW7BoY6ozExsfQ%3D%3D'}


response=requests.get(url,headers=headers)

with open("gitHub.html",'wb')as f:
    f.write(response.content)

以上是加入cookie登陆自己的GitHub账号

7.4 Cookie参数的使用(在headers里拆分出来)

使用cookie参数保持会话

构建cookie字典

再请求的时候cookies字典赋值给cookie参数

import requests

url='https://github.com/dashboard'

#构建请求头(有cookie和user-agent)
headers={'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36 Edg/120.0.0.0'}

#构建cookie字典
temp ='_octo=GH1.1.1235221592.1689322009; _device_id=8525f19d21277cdad23852e7fc76e6a8; preferred_color_mode=light; tz=Asia%2FShanghai; has_recent_activity=1; saved_user_sessions=147335186%3AaxSCC7rbNerhoWRJQRlZJLpGCuObDSRNaGy8x39wnBsypbJu; user_session=axSCC7rbNerhoWRJQRlZJLpGCuObDSRNaGy8x39wnBsypbJu; __Host-user_session_same_site=axSCC7rbNerhoWRJQRlZJLpGCuObDSRNaGy8x39wnBsypbJu; tz=Asia%2FShanghai; color_mode=%7B%22color_mode%22%3A%22auto%22%2C%22light_theme%22%3A%7B%22name%22%3A%22light%22%2C%22color_mode%22%3A%22light%22%7D%2C%22dark_theme%22%3A%7B%22name%22%3A%22dark%22%2C%22color_mode%22%3A%22dark%22%7D%7D; logged_in=yes; dotcom_user=akdhjss; _gh_sess=yBi7IBMRNgP4yMYJgTf2FlQ4WF1%2BCC%2F2GRxw7ckEm2rr1%2FWiSv3%2BEmZoLpOvmxiex%2F27SfcszIpUKUDEGfBD2s9M1Wyrs%2FltrFvkLLQdGL4chDMM2H0B5fBgqMv%2FaG2gT4UyoDCQ3JjIsmxvDmyJHhsejXAcDAsps9lB7FuAE6xN1RsbMebjjjY5lYHEE%2FGyjDIA2bnsYearI9qV24hcgMn23Xcg7Viztv5nkIvk8Zdq7QunEnqI76XuLM1jVSS9blDU12DKzejwqmggCQwxoTK25Otl5z3Mo6tS5nVKHEN1mkd5jENmcYrQY%2BPmCyVHJnJgxfSl%2FkJQvz%2BZrqt8JQgTpNoNnn%2B8HPA3reWVfsnniQrZxn9DIpiwMHwh0CRS2f2UsDrSBF%2Bx3qrzr6cI%2Bpzm3nz86LuHvlsV8rnelhO4CcbDMP%2BqcfOUIbxiXH31v3MfqmRo9qi2QOMPPsEgUum6t4d%2FF%2FdfjrTtTTdj65xmx2yk0EMNi%2Fk2SMMXuNwlTQGse2Po9fpOmxUfxjslqynUXWyzDeII2lRSSIUdVunFxUqwugvkA0981zqN1rPSAPNVyJoU3FdPVPVw6Y5pSWPHHbYXK1%2Fk%2BC58NBqgNB9wRjZLTlv3aoFnhg4b2vF2IfeqwjE3IIxeE8s5lZgRqYKrzxqN1ZLllPw9yPUWOG%2BySnv0Rncj5FqDsGzwbVpD2yKZhIJM6Bw%2BILGgPWJHBZpIwJ0B%2BGQRmf3%2BxGoJyCWcIr6%2FI%2Bw6937HIUTGO7ppsvCfqum1dbqfNcWVdASbcRct16qGaMYiU1K6r49yGhZB4pXHUkLMSSEPa9qW5GfaQsqeJLyP0TTvgk7j--8TkhBAxrKqmF5sPy--G%2FpHF6X3KW7BoY6ozExsfQ%3D%3D'

#稳妥方案
cookie_list=temp.split(';')
cookies={}
for cookie in cookie_list:
    cookies[cookie.split('=')[0]]=cookie.split('=')[-1]

response=requests.get(url,headers=headers,cookies=cookies)
print(response.content.decode())

7.5 CookieJar对象转换为cookies字典的方法

import requests

url='http://www.baidu.com'

response=requests.get(url)

dict_cookies = requests.utils.dict_from_cookiejar(response.cookies) #将请求得到的cookie转换为字典类型
print(dict_cookies)
jar_cookie = requests.utils.cookiejar_from_dict(dict_cookies) #将字典类型转换为cookie对象
print(jar_cookie)
#以上两种方法都会丢失域名

8.超时参数timeout的使用

import requests

url='http://twitter.com'

response = requests.get(url,timeout=3) #设置timeout,表示三秒后若没有访问成功就报超时

9.代理IP

9.1 含义

1.代理ip是一个ip,指向的是一个代理服务器

2.代理服务器能够帮我们向目标服务器发送请求

9.2 作用

帮忙转发

9.3 正向代理和反向代理

正向代理:浏览器知道最终服务器的地址

反向代理:浏览器不知道最终服务器的地址

9.4 代理ip的分类

1.透明代理

2.匿名代理

3.高匿代理

高匿代理是最好的!!!

按协议分:

1.http代理

2.https代理

9.5 使用

request.get(url,proxies=proxies)

参数传给proxies

proxies的形式:字典

格式必须如下(有严格要求)

proxies={

‘http’:‘http://12.34.56.78:9527’,......

}

代理使用成功不会有任何错误,能获取响应

如果失败,要么卡顿,要么报错

实例:

import requests

url='http://www.baidu.com'

proxies={
    'http':'58.220.95.54:9400',
     'https':'58.220.95.54:9400'
}
response=requests.get(url,proxies=proxies)


print(response.content.decode())

10.使用verify参数忽略CA证书

就是网页会说不是私密连接,要按隐藏信息才可以继续访问

直接爬取会报错,只需要添加以下代码即可解决

response=requests.get(url,verify=False)

即将verify参数改为False

11.使用request模块发送post请求

方法:

response=requests.post(url,data)#data是一个字典,必须要有

其他参数和之前的都一样

实例:爬取百度翻译接口(要用post,post才不会改变网址)

import requests
import re
class goldMine():
    def __init__(self,word):
        self.sum=0  #计算一下该单词翻译后的个数
        self.url = 'https://fanyi.baidu.com/sug' #翻译的网站
        self.headers = {'Referer':      #跳转翻译的网站需要经过该网站,不然会报错,加入user-agent
'https://fanyi.baidu.com/mtpe-individual/multimodal?channel=pcHeader','User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'}
        self.data={'kw':word}

    def __translation_Process(self):
        response=requests.post(self.url,headers=self.headers,data=self.data)#使用post请求,该请求不会改变网址
        result=response.content.decode()  #得到响应结果
        mode_of_operation = '"v":"([\w][\S\s]*?)"}' #编写正则表达式的规则
        r = re.findall(mode_of_operation,result) #使用正则表达式过滤出需要的内容,即翻译后的单词
        for x in r:                         #遍历翻译后的每一个单词
            temp = x.split(";")
            for y in temp:
                self.sum+=1
                print(str(self.sum)+'.'+y.lstrip())  #用lstrip()方法去除字符串开头的空格
        if self.sum == 0:
            print("抱歉,翻译失败")

    def run(self):
        #编写爬虫逻辑
        #url
        #headers
        #data字典
        #发送请求获取响应
        #数据解析
        self.__translation_Process()

temp = input("请输入要翻译的单词:")
test = goldMine(temp)
print("翻译的结果为:")
test.run()

1.实现方法

request.post(url,data)

data是一个字典

2.post 数据来源

​ 1.固定值 抓包比较不变值

​ 2.输入值 抓包比较根据自身变化值

​ 3.预设值—静态文件 需要提前从静态html中获取

​ 4.预设值—发请求 需要对指定地址发送请求

​ 5.在客户端生成的 分析js,模拟生成数据

11.1 requests.session模块

作用:自动处理cookie,会带上上次的cookie

使用场景:连续多次请求

使用方法:session=requests.session()#实例化session对象

​ response=session.get(url,headers,......)

​ response=session.post(url,headers,......)

session对象发送get或post请求的参数,与request模块发送请求的参数完全一致(只是会保持cookie,其他和request操作一样)

以下为登录github的实例

import re

import requests

import time

def login():
    #session
    session=requests.session()
    #headers session对象可以直接赋值头部
    session.headers={'User-Agent':
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Mobile Safari/537.36 Edg/121.0.0.0'}
    #url1 获取token
    url1='https://github.com/login'
    #发送请求,获取响应
    response1=session.get(url1).content.decode()
    #正则提取
    root_mode = 'token" value="([\s\S]*?)"'
    token = re.findall(root_mode,response1)[0]
    print(token)
    #url2 登录
    url2 = 'https://github.com/session'
    #构建表单字典
    data = {'commit': 'Sign in',
    'authenticity_token': token,
    'nM902xQOiKUw' : '',
    'login': 'EmilySanchezgd68 @ gmail.com',
    'password': 'Ljr1218.',
    'webauthn - conditional': 'undefined',
    'javascript - support':'true',
    'webauthn - support': 'supported',
    'webauthn - iuvpaa - support': 'unsupported',
    'return_to': 'https: // github.com / login',
    'allow_signup':'',
    'client_id':'',
    'integration':'',
    'required_field_47e1':'',
    'timestamp': 1706509326079,
    'timestamp_secret': 'c932e751aabb495a49987d127544ea39bdf00ad29b42e63848a2042f9acc2781',
    }

    session.post(url2,data=data)
    #url3 验证
    url3 = 'https://github.com/akdhjss'
    response3 = session.get(url3)
    with open("Github.html",'wb') as f:
        f.write(response3.content)



login()

12.数据提取

12.1 响应分类

结构化 :

​ json 数据(高频出现)

​ json模块

​ re模块

​ xml数据(低频出现)

​ re模块

​ lxml模块

非结构化:

​ html

​ re模块

​ lxml模块

xml以及和html的区别

​ xml传输和存储数据

​ html展示数据

常用数据解析方法:略

12.2 jsonpath模块

使用场景:多层嵌套的复杂字典直接提取数据

安装:pip install jsonpath

使用方法:

from jsonpath import jsonpath
ret = jsonpath(a,jsonpath语法规则字符串)#a是字典

语法:$ 根结点(最外层的大括号)

​ . 直接子节点

​ .. 内部任意节点,子孙节点

举例:

from jsonpath import jsonpath

data = {"1":{"1":{"1":{"1":{"1":{"1":'python'}}}}}}

ret = jsonpath(data,'$.1.1.1.1.1.1') # 一级一级索引

ret1 = jsonpath(data,'$..1') #跨越索引

print(ret,ret1)

12.3 lxml模块

lxml $ xpath

xpathhelper

作用

​ 对当前页面测试xpath语法规则

安装

使用:

/绝对路径

//相对路径

不同标签就是用/或者//来分割 类似于jsonpath的语法一样

.是选取当前节点

..是上一层节点

/text() 从开闭标签之间选取文本信息

//link/@href 从选中的节点标签中获取指定属性的值

节点修饰语法

1.通过索引修饰节点 :用[ ] 下标从1开始,last()是选出来的节点个数,若[last()]就是选中最后一个节点,positio()>=10 序号大于十的的节点

2.通过属性值修饰节点

//div[@id='content-left']/div/@id 出现在[]中的@是标签属性名和属性值,最后的@是选取该属性的值

3.通过子节点的值修饰节点

//div[span[2]=9.6] span是子节点 ,div是父节点

4.通过包含修饰

//a/span[contains(text(),"泰坦")]

用contains(选取的内容,包含的内容) 既可以属性包含也可以标签内容包含

| xpath复合 或的意思 两边写两个语句

下载lxml

导入lxml的etree库

from lxml import etree

利用etree.HTML,将html字符串(bytes类型或str类型)转化为Element对象,Element对象具有xpath的方法,返回结果列表

html=etree.HTML(text)
ret_list = html.xpath("xpath语法")

zip函数可以了解一下,两个列表按同一个下标成对输出

找下一页的时候尽量不要索引

百度贴吧爬虫实例

import requests

from lxml import etree

class TieBa():

    def __init__(self,name):

        self.url = 'https://tieba.baidu.com/f?kw={}'.format(name)

        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36','Cookie':
'BAIDUID=7CC8361ED10F5BB69724FE03ED51758C:FG=1; BAIDUID_BFESS=7CC8361ED10F5BB69724FE03ED51758C:FG=1; BIDUPSID=7CC8361ED10F5BB69724FE03ED51758C; PSTM=1707025702; H_PS_PSSID=39996_40125_40203_39661_40207_40217_40222; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BAIDU_WISE_UID=wapp_1707026878823_444; PSINO=3; delPer=0; Hm_lvt_98b9d8c2fd6608d564bf2ac2ae642948=1707026876,1707036702,1707121969; USER_JUMP=-1; st_key_id=17; arialoadData=false; video_bubble0=1; BDUSS=DZ0TGl4MTNBaGttV3cyOWdDa1RNMDVUZkNqNURZc3oxem51QlpnNFBWOE5MT2hsSVFBQUFBJCQAAAAAAAAAAAEAAADiHbtQtq--1sT-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2fwGUNn8Ble; BDUSS_BFESS=DZ0TGl4MTNBaGttV3cyOWdDa1RNMDVUZkNqNURZc3oxem51QlpnNFBWOE5MT2hsSVFBQUFBJCQAAAAAAAAAAAEAAADiHbtQtq--1sT-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2fwGUNn8Ble; STOKEN=0c63ee151abc52c81e9c152a0e3a8c560c7dac82ebf23a987896d19a84b535ac; 1354440162_FRSVideoUploadTip=1; video_bubble1354440162=1; wise_device=0; ZFY=:B3i7R8iYw1exq2vLNDjRxmt:B6qjggDd56ZS60b:Awbk4:C; tb_as_data=7b1190933332ef13c84ba157eec9ac7fec8837bb19f848776a218ec5911f71f35058518892129cebe49e096f3a3ac2ad68d5673da7132d7ef11f78acea72c988b92c227ad3e63316f5e544765e154a3522b177b43fec4aa2726fcfb50576e5a089cf42152219bab52d35661ea8eacc24; Hm_lpvt_98b9d8c2fd6608d564bf2ac2ae642948=1707130731; XFI=8c18d8e0-c415-11ee-8c73-ef3bfa4b2051; BA_HECTOR=058101052524ak84808ga4ak97blj71is1frc1s; ab_sr=1.0.1_MGM4OGY5MmNiNjNmYmYxYmE5NDhiMDAyNTNkNTBmZGNkNjBlNmVkMzM5MjZlOTcxZjVjZTYyM2ZiNDhiOWM4Nzc0MmQ3MGViOGFlNGUwZmExZWNiMzM0ZTViYmFhMmRlOWRjZTc2YzAzODYwZWM1OTNjOWU5Y2Q2MDAwNGYzMTk1NTA4Y2M3MmVjMDkzODQ0YzQyMmYwOTkzYWMwYTc4MGViNWEzZTE0MWU3OTZmNzllNmIxMzlmYjY1NmJjZGQ5; st_data=a755dd839b7e991e8759489ce82cf0f75fd26b55baa87ca4305caddd45a5d05c29f8b917745f49a9fd27310ad81b35b4b1863f0f8ac8ba65fd31041bfb80be4d25243347a21b0675b3c0fe53df8162c4f329632fc3298428c4f7b9a225bb8cdd4132a6434e035e8d957f4443d04c74e1768123b80b5be2d1e44dd366028c87e58d9df5659b84fbeeb1469221849ffc23; st_sign=4afb4150; XFCS=DD6C5275F46AEC805CE9DC5C7DE3092E09832B778BD4857AE09A2ADA83F059A2; XFT=lqGoKUfB/3lFZD83d6I0RzYSp4DPeRajRdTPD3/2ARc=; RT="z=1&dm=baidu.com&si=17ee4ecd-cb8e-4d3c-aee0-6d0c1796dac5&ss=ls8occy8&sl=2r&tt=1dua&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=57vta&ul=586c8"'}



    def get_data(self,url):

        response = requests.get(url,headers = self.headers)


        with open('baidutieba.html','wb') as f:
            f.write(response.content)

        return response.content.decode()

    def prase_data(self,data):

        # -->是html的注释

        # 可以用repalce进行解除注释,即如下,或者可以换一个低端的浏览器请求头。如:User-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;

        data = data.replace('<!--','').replace('-->','')

        html = etree.HTML(data)


        ret_list = html.xpath('//li/div/div[2]/div[1]/div[1]/a')

        # print(len(ret_list))

        #提取数据
        data_list = []


        for ret in ret_list:
            temp = {}

            temp['title'] = ret.xpath('./text()')[0]

            temp['link'] = 'https://tieba.baidu.com' + ret.xpath('./@href')[0]

            data_list.append(temp)

            #获取下一页


        # print(data_list)


        #使用 append() 函数添加列表时,是添加列表的「引用地址」而不是添加列表内容,当被添加的列表发生变化时,添加后的列表也会同步发生变化。
        # print(html)
        # print(html.xpath('//a[@class="next pagination-item "]'))
        t=html.xpath('//a[@class="next pagination-item "]')[0]
        try:
            next_url = 'https:'+t.xpath('./@href')[0]
        except:
            next_url = None
        # print(next_url)


        return data_list,next_url

    def saveData(self,data_list):

        with open("百度网盘爬虫.txt",'a',encoding='utf-8')as f:
            f.write(data_list)



    def run(self):
        # url
        # headers
        # 发送请求,获取响应
        next_url = self.url
        print('保存中')
        while True:
            data = self.get_data(next_url)
            #从响应中获取数据,和翻页url
            data_list,next_url = self.prase_data(data)
            #判断是否终结

            self.saveData(str(data_list))
            if next_url == None:
                print('爬取完成')
                break
tieba = TieBa('李毅')

tieba.run()