Loading

Loading

爬虫入门笔记!

爬虫入门笔记!✨

1.信息的请求与收集

网络爬虫指的是能够自动化访问网站的程序,其目的一般是提取和保存网页信息

网络爬虫的一般流程:

  1. 获取网页

  2. 解析网页

  3. 存储数据

建议前置知识:python基础+html

2.获取网页

img

  • requests.get()函数

    Requests 库内置了很多函数来帮我们实现各种方法的网络请求,像 requests.get()就是 Requests 库中用来发起 GET 请求的函数。

    而get则是网络请求方法的一种。

    img

  • URL(统一资源定位符)

包含协议、主机域名和路径

img

  • http与https的区别:

    http 是一种从网络传输数据到本地浏览器的传送协议,我们一般也称它为 http 协议。一般来说网络请求可以被称作http请求。

    而 https 协议会在 http 协议的基础上对数据进行加密处理,相对于 http 来说更加安全、可靠。

  • 响应

    requests.get() 函数返回结果是一个属于 requests.models.Response 类的对象。

    Response 就是英文里响应的意思,Response 对象顾名思义,就是一个包含各种网络请求响应信息的对象。

    服务器返回给浏览器的内容,主要包含了响应状态码响应头响应体等信息。

    img

  • response对象的status_code属性(状态码)

    import requests
    # 发送请求,并把响应结果赋值在变量res上
    res = requests.get('https://www.baidu.com/')
    # 打印Response对象的status_code属性,即状态码
    print(res.status_code)
    #运行结果:200(请求成功)
    
  • robots协议

    想要查看某个网页的robots协议,只需要在网站的主机域名后加上/robots.txt即可

    在 Robots 协议中,User-agent代表的是爬虫身份。

    比如User-agent: Baiduspider代表的就是百度的爬虫,User-agent: *代表的是未指定身份的所有爬虫,像我们就属于User-agent: *

    Robots 协议对于不同的爬虫身份有着不一样的限制。

    Disallow:声明了网站禁止百度爬虫爬取的内容。冒号后面代表限制爬虫的路径。

    Disallow:/表示禁止百度爬取https://wp.forchange.cn/下的所有内容。

    不过这些我们不用担心,禁止只是百度爬虫。我们只需要查看下面User-agent: *的限制。

    首先我们看到一个跟百度爬虫一样的Disallow: /,这里并不意味着我们对于网站的爬取受到了限制。

    因为往后看,我们还能看到一些Allow的路径。

    例子:淘宝的robots协议的url为https://www.taobao.com/robots.txt

    User-agent: Baiduspider
    Disallow: /
    
    User-agent: baiduspider
    Disallow: /
    

    虽然Robots协议只是一个道德规范,和爬虫相关的法律也还在建立和完善之中,但我们在爬取网络信息时,应该有意识地去遵守这个协议。

    网站的服务器被频繁访问,也会受到较大的压力,因此,各大网站也会做一些反爬虫的措施。不过呢,有反爬虫,也就有相应的反反爬虫。

3.解析网页

解析数据需要使用bs4库。

bs4 库是一个可以方便地从 HTML 文档中提取数据的 Python 第三方库,通常也称为“Beautiful Soup库”,bs4的4表示版本。

解析 HTML 文档的工具是解析器。就像建筑图纸有一本使用说明书,如果说 HTML 文档是搭建网页的建筑图纸,那解析器就是 HTML 文档的使用说明书,这份说明书是给程序用的。

解析 HTML 文档的过程就是实例化 BeautifulSoup 类,得到 BeautifulSoup 对象的过程。

这个过程很简单:先导入 bs4 库中的 BeautifulSoup 类,然后实例化 BeautifulSoup 类。

from…import…语句可以导入 bs4 库中的 BeautifulSoup 类。

from bs4 import BeautifulSoup

img

第 1 个参数可以是字符串格式的 HTML 文档,指示要解析的内容;第 2 个参数可以是解析器的名字,用来标识怎样解析文档。

第一个参数要注意一下,数据类型是字符串。我们获取网页得到的是包含 HTML 文档的 Response 对象,需要调用 Response 对象的 text 属性(即Response 对象.text),得到 HTML 文档的字符串形式。

第二个参数,要传入解析器的名字,也是字符串类型,我们用到的解析器是'html.parser'。

BeautifulSoup 也支持其他类型的解析器,不同的解析器有不同优缺点

img

我们可以使用以下的代码解析网页:

# 导入 requests 库
import requests
# 从 bs4 中导入 BeautifulSoup 类
from bs4 import BeautifulSoup

# 百度网页的 URL
url = 'https://www.baidu.com'
# 请求网页,并将结果赋值给变量 res
res = requests.get(url)
# 打印响应状态码,查看是否请求成功
print(res.status_code)
# 设置响应内容的编码格式
res.encoding = 'utf-8'

# 用 BeautifulSoup 和解析器'html.parser'解析请求到的网页
bs = BeautifulSoup(res.text,'html.parser')

# 打印查看解析结果
print(bs)

解析完网页之后,可以试着用BeautifulSoup 对象.元素名取任意节点。

如要取的有很多节点,则会取到第一个节点。

.元素名操作还有一个拓展用法:.元素名.元素名.……,BeautifulSoup 对象和 Tag 对象都可以这样操作。

img

  • find_all() 和 find() 方法

    find_all()方法:搜索所有满足条件的 Tag 对象。

    返回的结果是一个类似列表的可迭代对象,里面包含了所有满足参数条件的 Tag 对象。

    可以从 BeautifulSoup 对象中找,也可以从 Tag 对象中找。

    • 如果从 BeautifulSoup 对象中搜索,语法是:BeautifulSoup 对象.find_all()

    • Tag 对象中搜索,语法是:Tag 对象.find_all()

find_all() 方法的参数就是需要满足的条件。我们主要用到两种参数:HTML 元素名和 HTML 元素属性。

  1. html元素名

    传入HTML 元素名作为 find_all() 方法的参数,即可搜索所有元素名匹配的 Tag 对象。

    用元素名查找对应的 Tag 对象时,每次只能传入一个元素名,而且要以字符串的形式传入。

    例如:BeautifulSoup 对象.find_all('div'),可以获取 BeautifulSoup 对象中所有的<div>元素

    下面代码中的html可以替换为实例化对象.text。(需要转编码为utf-8)

    # 解析 HTML 文档
    bs = BeautifulSoup(html, 'html.parser')
    # 用find_all()获取所有<div>节点
    div_all = bs.find_all('div')
    
  2. html元素属性

    传入 HTML 元素属性时,要用参数名 = 参数值的形式,一次可以传入 0 到多个属性。参数名通常是元素的属性名,参数值就是对应的属性值。

    这里需要注意的是:HTML 的 class 属性与 Python 的保留关键字 class 重复。因此,作为参数使用 class 属性时,要加一个_,写作class_,避免混淆。

    例如:BeautifulSoup 对象.find_all(class_='poems')用来搜索 BeautifulSoup 对象中,所有拥有属性class='poems'的元素对应的 Tag 对象。

    下面代码中的html可以替换为实例化对象.text。(需要转编码为utf-8)

    bs = BeautifulSoup(html, 'html.parser')
    # 用find_all()获取所有含属性class="poems"的HTML元素对应的节点
    poems_all = bs.find_all(class_='poems')
    

由于 find_all() 返回的都是满足所有参数条件的 Tag 对象,因此,可以结合使用上述两种参数,更准确定位到 Tag 对象。同时使用 HTML 元素名和 HTML 元素属性作为搜索条件时,要把 HTML 元素名作为第 1 个参数,后面接 0 到多个 HTML 元素属性。

例如,想在 BeautifulSoup 对象中搜索所有元素名为div,并且拥有属性class="poems"的元素对应的 Tag 对象,语法应该是:BeautifulSoup 对象.find_all('div', class_='poems')

需要注意的是,find_all() 返回的结果并不是 Tag 对象,而是 Tag 对象组成的一个类似列表的可迭代对象。要拿到其中的 Tag 对象,通常需要for 循环来帮忙。

find()方法:大部分和find_all()一样。唯一不同的是,find() 方法返回的结果是一个 Tag 对象,搜索范围内,满足参数条件的第一个 Tag 对象。这一点和元素名操作有点儿像。

img

img

  • 我们还可以使用属性名脱去<>的外壳
h2_text = poem1_tag.find('h2').text
  • 提取对应元素的元素属性

接下来看,提取对应元素的元素属性:

提取 Tag 对象对应元素的属性,和用字典的键获取值的方式很像,用方括号。

语法是:Tag 对象['属性名'],可用来提取对应元素的属性值。

import requests
from bs4 import BeautifulSoup

# 获取网页
# 《乌合之众》网页的 URL
url = 'https://wp.forchange.cn/psychology/11069/'
# 请求网页
res = requests.get(url)
# 打印响应的状态码
print(res.status_code)
# 将响应内容的编码格式设置为utf-8
res.encoding = 'utf-8'

# 解析网页
# 解析请求到的网页,得到 BeautifulSoup 对象
bs = BeautifulSoup(res.text, 'html.parser')

# 搜索书籍信息的父节点<div>
info_tag = bs.find('div', class_='res-attrs')
# 搜索每条信息的节点<dl>
info_list = info_tag.find_all('dl')

# 遍历搜索结果,在<dl>节点中继续提取
for info in info_list:
    # 用.text提取信息提示项<dt>的元素内容
    dt = info.find('dt').text
    print(dt)
    # 用.text提取书籍信息<dd>的元素内容
    dd = info.find('dd').text
    print(dd)

梳理一下从获取网页到提取数据的流程:

img

img

易错点:(二者不一样)

  1. 获取 Tag 对象对应的 HTML 元素的属性值的语句为Tag 对象['属性名']
  2. 通过点号 .BeautifulSoup对象.元素名 语句来获取 Tag 对象
from bs4 import BeautifulSoup

html = '''
      <h1>
      <span property="v:itemreviewed">复仇者联盟4:终局之战 Avengers: Endgame</span>
          <span class="year">(2019)</span>
      </h1>
      <span><span class="pl">导演</span>
      ':' 
        <span class="attrs">
          <a href="/celebrity/1321812/" rel="v:directedBy">安东尼·罗素</a>
          / 
          <a href="/celebrity/1320870/" rel="v:directedBy">乔·罗素</a>
        </span>
      </span>
      <span><span class="pl">编剧</span>
      ':' 
        <span class="attrs">
          <a href="/celebrity/1276125/">克里斯托弗·马库斯</a>
          / 
          <a href="/celebrity/1276126/">斯蒂芬·麦克菲利</a> 
          / 
          <a href="/celebrity/1013888/">斯坦·李</a> 
          / 
          <a href="/celebrity/1050183/">杰克·科比</a> 
          / 
          <a href="/celebrity/1360715/">吉姆·斯特林</a>
        </span>
      </span>
      <span class="actor">
        <span class="pl">主演</span>
        ':' 
        <span class="attrs">
          <span><a href="/celebrity/1016681/" rel="v:starring">小罗伯特·唐尼</a> / </span>
          <span><a href="/celebrity/1017885/" rel="v:starring">克里斯·埃文斯</a> / </span>
          <span><a href="/celebrity/1040505/" rel="v:starring">马克·鲁弗洛</a> / </span>
          <span><a href="/celebrity/1021959/" rel="v:starring">克里斯·海姆斯沃斯</a> / </span>
          <span><a href="/celebrity/1004568/" rel="v:starring">乔什·布洛林</a> / </span>
        </span>
      </span>
      '''
bs = BeautifulSoup(html, 'html.parser')

movie_name = bs.find('span', property="v:itemreviewed").text

director = []
director_list = bs.find_all('a', rel="v:directedBy")
for i in director_list:
    director.append(i.text)

actor = []
actor_list = bs.find_all('a', rel="v:starring")
for i in actor_list:
    actor.append(i.text)
    
movie_dict = {'电影名':movie_name,'导演':director,'主演':actor}
print(movie_dict)

4. 存储数据

先来爬取书名:

image

通过上图,我们发现通过<a>可以找到书名相关的连接,类名。

使用

bookname_list = bs.find_all('a', class_='post-title')

可以定位到

# 导入库 requests 以及类 BeautifulSoup  
import requests  
from bs4 import BeautifulSoup

# 设置网站书籍列表页第 1 页的链接
url = 'https://wp.forchange.cn/resources/page/1/'
# 请求网页
res = requests.get(url)
# 解析网页得到 BeautifulSoup 对象,赋给变量 pybs
bs = BeautifulSoup(res.text, 'html.parser')
# 搜索网页中所有包含书籍名和书籍链接的 Tag
bookname_list = bs.find_all('a', class_='post-title')

# 遍历搜索结果,提取并打印书籍名和书籍链接
for bookname in bookname_list:
    # 使用 Tag.text 属性提取书籍名,并打印书籍名
    print(bookname.text)
    # 使用 Tag['属性名'] 提取书籍链接,并打印书籍链接
    print(bookname['href'])

接下来进入存储环节。先复习一下csv。

img

在存储上会更倾向于使用 csv 模块的 DictWriter()

调用 csv 模块中类 DictWriter 的语法为:csv.DictWriter(f, fieldnames),执行后会得到一个 DictWriter 对象。语法中的参数 f 是 open() 函数打开的文件对象;参数 fieldnames 用来设置文件的表头。

得到的 DictWriter 对象可以调用 writeheader() 方法,将 fieldnames 写入 csv 的第一行。

再调用 writerows() 方法将多个字典写进 csv 文件中。

5.带headers请求

headers即为请求头,目的是获得网页的访问许可。

eg:如果直接用requests来访问会返回418status_code的网站,比如豆瓣。

网络请求会将浏览器信息储存在请求头(Request Header)当中。

只要我们将浏览器信息复制下来,在爬虫程序只要在发起请求时,设置好与请求头对应的参数,即可成功伪装成浏览器。

我们打开豆瓣后台的网络界面,按Ctrl+R,会出现以下界面。

image

一定记住要勾选保存日志:

image

数据上面有状态栏(edge已经翻译为中文,下图为英文)

image

img

我们重点找的是最先出现的document格式的文件,这一般就是我们看到的网页界面。

当然,也可以通过筛选功能选择Doc格式的文件,这样在网页加载信息太多时,可以查找更加方便。

继续,点击这个document文件的name,再点击它的preview选项卡,查看是否含有我们想要爬取的信息。

通过观察可以判断我们找对了文件,再切换到Headers选项卡。

暂时先忽略其他信息,重点看Request Headers

这代表着"请求头",也就是浏览器证明自己身份的信息。

在请求标头中找到最下方的User_Agent

image

Request Headers中,除了User-Agent,还有Accept、Host、Cookie 等信息。

img

将网页中Request Headers里的信息用一个字典保存起来,然后再将这个字典传递给 get() 函数里的headers参数,就可以让 get() 函数伪装成“小红帽”的样子去拜访“外婆”。

我们查询到headers的内容如下:

image

如下,使用headers再次请求访问。输出为200状态码,请求成功。

import requests

# 设置要请求的网页链接
url = 'https://movie.douban.com/top250?start=0&filter='

# 设置请求头
headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0'
}

# 请求网页
res = requests.get(url, headers=headers)

# 打印网页状态码
print(res.status_code)

img

总结:

1)熟练地使用开发者工具的指针工具,可以很方便地帮助我们定位数据。

2)用指针工具定位到各个数据所在位置后,查看它们的规律。

3)想要提取的标签如果具有属性,可以使用 Tag.find(HTML元素名, HTML属性名='')来提取;没有属性的话,可以在这个标签附近找到一个有属性的标签,然后再进行 find() 提取。

通过上述步骤将信息爬取下来后,就走到我们爬虫的最后一步——存储数据。

img

6.模拟登录、爬取评论

之前的网络请求使用requests,现在我们使用post来完成。之所以不用get,是因为get会在网页链接中显示。

image

这里的登录请求我们看到是POST。

一般来说,请求可以分为四部分内容:请求网址、请求方法、请求头和请求体。

我们可以在负载中找到自己的登录信息。

image

POST()函数

img

url:传入的请求网址

data:传入的请求体,即我们上面在请求详情页的【Form Data】中看到的所有信息。这些信息在 Python 中可以以字典的形式来存储:

img

import requests

# 设置登录请求的请求网址
login_url = 'https://wp.forchange.cn/wp-admin/admin-ajax.php'
# 输入用户的账号密码
username = input('请输入用户名:')
password = input('请输入密码:')

# 设置登录请求的请求体数据
login_data = {
    'action': 'ajaxlogin',
    'username': username,
    'password': password,
    'remember': 'true'
}

# 请求登录网站
login_res = requests.post(login_url, data=login_data)
print(login_res.text)

cookies

Cookies 是网站为了辨别用户身份,进行会话跟踪而存储在用户本地的数据,由用户客户端计算机暂时或永久保存的信息。

首次登陆网站成功后,服务器会将 Cookies 信息返回给浏览器,浏览器将 Cookies 信息保存下来。

img

Cookies 里含有登录相关的信息,下次浏览器请求该网站的网页时,浏览器会将 Cookies 发送给服务器,服务器通过识别 Cookies 来判断发送请求的用户是否已登录。

img

怎么才能拿到服务器返回的 Cookies 信息呢?

我们只需要在“登录网站”的代码末尾,使用 post() 函数返回的 Response 对象,去调用它的 cookies 属性即可。(调用 cookies 属性时,注意开头的 c 为小写)

import requests

# 设置登录请求的请求网址
login_url = 'https://wp.forchange.cn/wp-admin/admin-ajax.php'
# 输入用户的账号密码
username = input('请输入用户名:')
password = input('请输入密码:')

# 设置登录请求的请求体数据
login_data = {
    'action': 'ajaxlogin',
    'username': username,
    'password': password,
    'remember': 'true'
}

# 请求登录网站
login_res = requests.post(login_url, data=login_data)

# 循环遍历获取到的 Cookies 信息
for cookie in login_res.cookies:
    # 打印 Cookies 信息
    print(cookie)
import requests

# 设置登录请求的请求网址
login_url = 'https://wp.forchange.cn/wp-admin/admin-ajax.php'
# 输入用户的账号密码
username = input('请输入用户名:')
password = input('请输入密码:')

# 设置登录请求的请求体数据
login_data = {
    'action': 'ajaxlogin',
    'username': username,
    'password': password,
    'remember': 'true'
}

# 请求登录网站
login_res = requests.post(login_url, data=login_data)

# 设置要请求的书籍评论页链接
comment_url = 'https://wp.forchange.cn/psychology/11069/comment-page-1/'
# 携带获取到的 Cookies 信息请求书籍评论页
comment_res = requests.get(comment_url, cookies=login_res.cookies)
# 打印获取到的网页内容
print(comment_res.text)
import requests
from bs4 import BeautifulSoup

# 设置登录请求的请求网址
login_url = 'https://wp.forchange.cn/wp-admin/admin-ajax.php'
# 输入用户的账号密码
username = input('请输入用户名:')
password = input('请输入密码:')

# 设置登录请求的请求体数据
login_data = {
    'action': 'ajaxlogin',
    'username': username,
    'password': password,
    'remember': 'true'
}

# 请求登录网站
login_res = requests.post(login_url, data=login_data)

# 设置要请求的书籍评论页链接
comment_url = 'https://wp.forchange.cn/psychology/11069/comment-page-1/'
# 携带获取到的 Cookies 信息请求书籍网页
comment_res = requests.get(comment_url, cookies=login_res.cookies)
# 解析请求到的书籍网页内容
soup = BeautifulSoup(comment_res.text, 'html.parser')
# 搜索网页中所有包含评论的 Tag
comments_list = soup.find_all('div', class_='comment-txt')

# 使用 for 循环遍历搜索结果
for comment in comments_list:
    # 提取用户名
    coment_name = comment.find('cite',class_='fn')
    # 打印用户名
    print(coment_name.text[:-2])

爬取评论的用户名:

import requests
from bs4 import BeautifulSoup

# 设置登录请求的请求网址
login_url = 'https://wp.forchange.cn/wp-admin/admin-ajax.php'
# 输入用户的账号密码
username = input('请输入用户名:')
password = input('请输入密码:')

# 设置登录请求的请求体数据
login_data = {
    'action': 'ajaxlogin',
    'username': username,
    'password': password,
    'remember': 'true'
}

# 请求登录网站
login_res = requests.post(login_url, data=login_data)

# 设置要请求的书籍评论页链接
comment_url = 'https://wp.forchange.cn/psychology/11069/comment-page-1/'
# 携带获取到的 Cookies 信息请求书籍网页
comment_res = requests.get(comment_url, cookies=login_res.cookies)
# 解析请求到的书籍网页内容
soup = BeautifulSoup(comment_res.text, 'html.parser')
# 搜索网页中所有包含评论的 Tag
comments_list = soup.find_all('div', class_='comment-txt')

# 使用 for 循环遍历搜索结果
for comment in comments_list:
    # 提取用户名
    coment_name = comment.find('cite',class_='fn')
    # 打印用户名
    print(coment_name.text[:-2])

img

7.刷评论

依旧是使用 post() 函数对网址发起请求。除了urldata外,发表评论是需要先登录的,所以我们还需要带上储存着登录信息的 Cookies

最终,我们发表评论中 post() 函数的语法格式应该是:requests.post(url, data, cookies)

posted @ 2025-08-10 22:57  Miya555  阅读(16)  评论(0)    收藏  举报