一、实现目标

        编写一个爬虫,获取豆瓣网站上“庆余年 第二季”这部电视剧的短评,网站如下:

# https://movie.douban.com/subject/34937650/comments?sort=new_score&status=P #

二、实现步骤

        我们在 Google Chrome浏览器中复制粘贴下面的链接,先看看网页内容,打开网页后可以看到,《庆余年 第二季》这部电视剧的相关短评,就在标注的红色方框内。这就是我们今天要获取的内容。

        想要获取网页中的短评,首先要获取网页 HTML 代码,再把短评从中提取出来。

2.1 获取网页源码

        获取网页中的 HTML 代码,我们可以使用 requests 模块的 get 方法来实现。

# 使用import导入requests模块
import requests

# 将豆瓣电影评论URL地址,赋值给变量url
url = "https://movie.douban.com/subject/34937650/comments?sort=new_score&status=P"

# 使用requests发起GET请求,赋值给response
response = requests.get(url)

# 使用print输出response.status_code
print(response)

        这里执行后返回的状态码是418,这意味我们的爬虫被服务端发现了,因为我们用的是 requests 发起的请求,而不是浏览器。

        我们需要加上User-Agent参数,伪装成一个浏览器。User-Agent参数值的获取方法也很简单,在chome浏览器中右键检查,在网络功能中可以看到客户端访问服务的请求,在请求头中包括本机的User-Agent参数,直接拿来用即可,如下图。

        将User-Agent参数的值以字典的形式的存储在headers参数中,然后在请求时带上headers参数。

# 使用import导入requests模块
import requests

# 将豆瓣电影评论URL地址,赋值给变量url
url = "https://movie.douban.com/subject/34937650/comments?sort=new_score&status=P"
# 将User-Agent以字典键对形式赋值给headers
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"}

# 使用requests发起GET请求,赋值给response
response = requests.get(url, headers=headers)

# 使用print输出response.status_code
print(response)

        然后响应状态码就变成了 200 ,这说明我们请求成功了。

        那么得到的网页内容在那能看到呢?网页的内容我们可以使用.text属性可以获取。但这个内容很长,不好分析,我们可以用切片的方法,先输出前1000个字符。

2.2 解析源码获取数据

        上一步获取到网页 HTML 代码。接下来,就需要解析网页,从网页中提取想要的数据。解析网页我们使用 BeautifulSoup 解析,这里就不需要做切片了,我们要解析整个网页内容。我们先导入 BeautifulSoup,并创建一个 BeautifulSoup 对象:

# 从bs4中导入BeautifulSoup
from bs4 import BeautifulSoup

# 使用BeautifulSoup()传入变量html和解析器lxml,赋值给soup
soup = BeautifulSoup(html, "lxml")

# 使用print输出soup
print(soup)

        接下来就要需要从 soup 中提取出短评所在的标签节点,我们可以使用 BeautifulSoup 中的 find_all() 函数,它可以查询所有符合条件的元素,并组成一个列表。

        在这里,find_all() 函数中传入的参数内容是什么呢?我们需要去网页中找到短评所在的节点。定位方法如下图:

        仔细观察发现,所有的评论都在 <span> 标签中,查找span标签在网页中出现了100多次,而显然,该页只有二十条评论。也可以试试以 <p> 节点来定位,网页中p标签出现的次数也大于20。那么我们该定位哪个节点,才能提取评论呢?

        多对照几条评论我们发现,短评所在的节点都是类似的它们都有一样的标签和属性,如下图所示。


        在 HTML 中,span 标签的作用是用来组合文档中的行内元素。class 属性的作用是用来给标签分类。class="short"也就代表着,这里标签的内容是短评。

        在网页中属性需要使用 (点).属性值 来定位。例如,图中我们在检索框中输入 .short 进行搜索,就能看到该页中 class="short" 属性出现的次数为20次,这些就是我们想要的内容。

        那么,就定位到了提取评论的节点 class="short" 。以属性为查询条件就需要在 find_all() 中,传入 class="short"。由于 class 在 Python 里是一个关键字 ,所以后面需要加一个下划线,即 class_="short"。

# 使用find_all()查询soup中class="short"的节点,赋值给content_all
content_all = soup.find_all(class_="short")

        如下图,我们获得了一个带标签的短语列表。

        标签对我们来说没有用,我们需要去掉它,拿到标签里的内容, 访问 .string 获取每个节点中标签的内容。由于 find_all() 返回的是一个列表,我们不能直接访问 .string 属性。需要使用 for 循环遍历列表 content_all。

for content in content_all:
    # 使用.string获取标签里的内容
    contentString = content.string
     
    # 使用print打印评论    
    print(contentString)

        如下图,我们就获得了第一页的20条评论

2.3 保存评论

        为保存评论,我们在前面定义一个 comments 列表,用于临时存储评论内容,在最后使用with open() 将 comments 列表的中的评论写入本地的.txt文件中。

# 定义一个列表,保存评论
comments = []

......

    # 保存评论到新的列表中
    comments.append(contentString)


# 保存评论到txt文件中
with open("D:/学习资料/Python/VSCode/yequbiancheng/网络爬虫/豆瓣评论_庆余庆.txt", "a", encoding='utf-8') as fp:
    # 将评论逐个写入txt文件中
    for comment in comments:
        fp.write(comment + "\n")
print("保存完毕")

        结果如下图

2.4 优化代码获取更多评论 

        现在我们获得了第一页的20条评论,可我们需要获得更多评论。我们点击后页,把每一页的URL地址拿出来对比一下。

        通过对比第一页的URL,我们发现除了第一页,其它都有两个共同的参数start和limit,很明显start表示的该页第一条评论的编号,limit是该页的评论条数。

       我们对URL进行一下改造,将limit设置为100,表示获取100条,使用 for 循环连续获取 5 页的评论。

for page in range(5):
    # 将豆瓣电影评论URL地址,赋值给变量url
    url = f"https://movie.douban.com/subject/34937650/comments?start={page*100}&limit=100&status=P&sort=new_score"

        完整的代码如下:

# 使用import导入requests模块
import requests
# 从bs4中导入BeautifulSoup
from bs4 import BeautifulSoup


# 使用for循环,获取前10页的评论
for page in range(5):

    # 定义一个列表,保存评论
    comments = []
    # 将豆瓣电影评论URL地址,赋值给变量url
    url = f"https://movie.douban.com/subject/34937650/comments?start={page*100}&limit=100&status=P&sort=new_score"
    # 将User-Agent以字典键对形式赋值给headers
    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"}

    # 使用requests发起GET请求,赋值给response
    response = requests.get(url, headers=headers)

    # 使用.text属性获取网页的内容,并赋值给html
    html = response.text

    # 使用BeautifulSoup()传入变量html和解析器lxml,赋值给soup
    soup = BeautifulSoup(html, "lxml")

    # 使用find_all()查询soup中class="short"的节点,赋值给content_all
    content_all = soup.find_all(class_="short")

    for content in content_all:
        # 使用.string获取标签里的内容
        contentString = content.string
        
        # 保存评论到新的列表中
        comments.append(contentString)

    # 保存评论到txt文件中
    with open("D:/学习资料/Python/VSCode/yequbiancheng/网络爬虫/豆瓣评论_庆余庆.txt", "a", encoding='utf-8') as fp:
        # 将评论逐个写入txt文件中
        for comment in comments:
            # 写入评论并回车
            fp.write(comment + "\n")
    print(f"第{page}页保存完毕")

        执行结果如下

三、总结

        本实例实现了庆余年的豆瓣电影评论爬取,使用了requests、bs4模块。

        requests:是一个常用的 HTTP 请求库,可以方便地向网站发送 HTTP 请求,并获取响应结果。requests 模块比 urllib 模块更简洁。

        bs4:全名 BeautifulSoup,是编写 python 爬虫常用库之一,主要用来解析 html 标签。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐