这篇文章,咱们继续利用 requests 和 xpath 爬取豆瓣电影的短评,下面仍是先贴上效果图:html
咱们仍是使用 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
这一次咱们须要的数据包括(这里仍是使用 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
下面将数据分别保存为 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 后应该尽快使用】
【爬虫系列相关文章】