這篇文章,咱們繼續利用 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 後應該儘快使用】
【爬蟲系列相關文章】