爬虫系列(十一) 用requests和xpath爬取豆瓣电影评论

这篇文章,咱们继续利用 requests 和 xpath 爬取豆瓣电影的短评,下面仍是先贴上效果图:html

一、网页分析

(1)翻页

咱们仍是使用 Chrome 浏览器打开豆瓣电影中某一部电影的评论进行分析,这里示例为《一出好戏》python

和以前同样,咱们能够经过构造 URL 获取所有网页的内容,可是此次咱们尝试使用一种新的方法 —— 翻页json

使用快捷键 Ctrl+Shift+I 打开开发者工具,而后使用快捷键 Ctrl+Shift+C 打开元素选择工具浏览器

此时用鼠标点击网页中的 后页,就会在源代码中自动定位到相应的位置网络

接下来咱们用 xpath 匹配下一页的连接地址:dom

html.xpath('//div[@id="paginator"]/a[@class="next"]/@href')

这样一来,咱们只要在每一页中经过循环不断获取下一页的内容便可工具

核心代码以下:url

# 获取网页源代码
def get_page(url):
    # 构造请求头部
    headers = {
        'USER-AGENT':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    }
    # 发送请求,得到响应
    response = requests.get(url=url,headers=headers)
    # 得到网页源代码
    html = response.text
    # 返回网页源代码
    return html

# 解析网页源代码,获取下一页连接
def parse4link(html,base_url):
    # 初始化返回结果
    link = None
    # 构造 _Element 对象
    html_elem = etree.HTML(html)
    # 匹配下一页的连接地址,注意,它是一个相对地址
    url = html_elem.xpath('//div[@id="paginator"]/a[@class="next"]/@href')
    # 若匹配成功,则将匹配结果与初始 URL 拼接,构成完整的连接地址
    if url:
        link = base_url + url[0]
    return link

(2)分析网页内容

这一次咱们须要的数据包括(这里仍是使用 xpath 进行匹配):spa

  • 赞同人数://div[@class="comment-item"]/div[2]/h3/span[1]/span/text()
  • 评论者://div[@class="comment-item"]/div[2]/h3/span[2]/a/text()
  • 评价://div[@class="comment-item"]/div[2]/h3/span[2]/span[2]/@title
  • 评论内容://div[@class="comment-item"]/div[2]/p/span/text()

核心代码以下:翻译

# 解析网页源代码,获取数据
def parse4data(html):
    # 构造 _Element 对象
    html = etree.HTML(html)
    # 赞同人数
    agrees = html.xpath('//div[@class="comment-item"]/div[2]/h3/span[1]/span/text()')
    # 评论做者
    authods = html.xpath('//div[@class="comment-item"]/div[2]/h3/span[2]/a/text()')
    # 评价
    stars = html.xpath('//div[@class="comment-item"]/div[2]/h3/span[2]/span[2]/@title')
    # 评论内容
    contents = html.xpath('//div[@class="comment-item"]/div[2]/p/span/text()')
    # 得到结果
    data = zip(agrees,authods,stars,contents)
    # 返回结果
    return data

(3)保存数据

下面将数据分别保存为 txt 文件、json 文件和 csv 文件

import json
import csv
# 打开文件
def openfile(fm):
    fd = None
    if fm == 'txt':
        fd = open('douban_comment.txt','w',encoding='utf-8')
    elif fm == 'json':
        fd = open('douban_comment.json','w',encoding='utf-8')
    elif fm == 'csv':
        fd = open('douban_comment.csv','w',encoding='utf-8',newline='')
    return fd

# 将数据保存到文件
def save2file(fm,fd,data):
    if fm == 'txt':
        for item in data:
            fd.write('----------------------------------------\n')
            fd.write('agree:' + str(item[0]) + '\n')
            fd.write('authod:' + str(item[1]) + '\n')
            fd.write('star:' + str(item[2]) + '\n')
            fd.write('content:' + str(item[3]) + '\n')
    if fm == 'json':
        temp = ('agree','authod','star','content')
        for item in data:
            json.dump(dict(zip(temp,item)),fd,ensure_ascii=False)
    if fm == 'csv':
        writer = csv.writer(fd)
        for item in data:
            writer.writerow(item)

二、代码实现

注意,本程序须要用户输入电影 ID,用于构造初始 URL ,例如:

若是电影的连接地址为:https://movie.douban.com/subject/26985127/comments?status=P

那么电影 ID 为:26985127

【PS:虽然这种作法对用户不太友好,可是因为我的水平以及时间问题,目前也还没想到比较好的解决方法,

最初的想法是让用户输入电影名称,而后由程序自动将电影名称映射为电影 ID,从而构造出初始 URL】

import requests
from lxml import etree
import re
import json
import csv
import time
import random

# 获取网页源代码
def get_page(url):
    headers = {
        'USER-AGENT':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    }
    response = requests.get(url=url,headers=headers)
    html = response.text
    return html

# 解析网页源代码,获取下一页连接
def parse4link(html,base_url):
    link = None
    html_elem = etree.HTML(html)
    url = html_elem.xpath('//div[@id="paginator"]/a[@class="next"]/@href')
    if url:
        link = base_url + url[0]
    return link

# 解析网页源代码,获取数据
def parse4data(html):
    html = etree.HTML(html)
    agrees = html.xpath('//div[@class="comment-item"]/div[2]/h3/span[1]/span/text()')
    authods = html.xpath('//div[@class="comment-item"]/div[2]/h3/span[2]/a/text()')
    stars = html.xpath('//div[@class="comment-item"]/div[2]/h3/span[2]/span[2]/@title')
    contents = html.xpath('//div[@class="comment-item"]/div[2]/p/span/text()')
    data = zip(agrees,authods,stars,contents)
    return data

# 打开文件
def openfile(fm):
    fd = None
    if fm == 'txt':
        fd = open('douban_comment.txt','w',encoding='utf-8')
    elif fm == 'json':
        fd = open('douban_comment.json','w',encoding='utf-8')
    elif fm == 'csv':
        fd = open('douban_comment.csv','w',encoding='utf-8',newline='')
    return fd

# 将数据保存到文件
def save2file(fm,fd,data):
    if fm == 'txt':
        for item in data:
            fd.write('----------------------------------------\n')
            fd.write('agree:' + str(item[0]) + '\n')
            fd.write('authod:' + str(item[1]) + '\n')
            fd.write('star:' + str(item[2]) + '\n')
            fd.write('content:' + str(item[3]) + '\n')
    if fm == 'json':
        temp = ('agree','authod','star','content')
        for item in data:
            json.dump(dict(zip(temp,item)),fd,ensure_ascii=False)
    if fm == 'csv':
        writer = csv.writer(fd)
        for item in data:
            writer.writerow(item)

# 开始爬取网页
def crawl():
    moveID = input('请输入电影ID:')
    while not re.match(r'\d{8}',moveID):
        moveID = input('输入错误,请从新输入电影ID:')
    base_url = 'https://movie.douban.com/subject/' + moveID + '/comments'
    fm = input('请输入文件保存格式(txt、json、csv):')
    while fm!='txt' and fm!='json' and fm!='csv':
        fm = input('输入错误,请从新输入文件保存格式(txt、json、csv):')
    fd = openfile(fm)
    print('开始爬取')
    link = base_url
    while link:
        print('正在爬取 ' + str(link) + ' ......')
        html = get_page(link)
        link = parse4link(html,base_url)
        data = parse4data(html)
        save2file(fm,fd,data)
        time.sleep(random.random())
    fd.close()
    print('结束爬取')

if __name__ == '__main__':
    crawl()

写完以后,咱们运行代码试一下效果:

咦?好像有点怪怪的,怎么只有 11 页评论?不科学呀,《一出好戏》这部电影明明有十多万条评论的呀

咱们直接用浏览器打开最后一个连接看一下:

原来,11 页以后的评论是须要登录以后才有权限访问的,没办法,那就只好再写一个模拟登录呗

咱们这里使用最最简单的方法进行模拟登录,那就是使用 Cookie,而且是手动获取 Cookie (懒)

简单来讲,Cookie 是为了记录用户信息而储存在用户本地终端上的数据

当咱们在浏览器上登录后,咱们登录的信息会被记录在 Cookie 中

以后的操做,浏览器会自动在请求头中加上 Cookie,说明这是一个特定用户发送的请求

那么怎样获取 Cookie 呢?也很简单,用浏览器打开 豆瓣电影首页 进行登录,而后进行抓包就能够

最后,咱们只须要把 Cookie 信息复制下来,放到请求头中一块儿发送,这样就能够继续愉快的爬取评论啦

【PS:注意 Cookie 的有效期,获取 Cookie 后应该尽快使用】

【爬虫系列相关文章】

相关文章
相关标签/搜索