用比較簡單的方法爬取豆瓣電影評論及電影詳情頁的一些內容。
爬取思路:
(1) 從電影的列表頁開始,獲取當前頁面每部電影的link;
(2) 通過觀察link的組成,從電影的link,獲得評論頁的起始頁link
(3) 在全部的短評頁面,獲取評論用戶id、評分、評論內容等,同時進行翻頁(在不登錄的情況下,目前只能翻到第十頁)。
代碼效果:
- 優點:運行簡單,不需要太多設置。
- 缺點:第(1)步目前還沒有實現自動翻頁;(2)受登錄限制,目前跑一陣大概就會出現403錯誤。
- 改進方向:多設置一些except error,或者是傳入cookie,或者通過模擬登錄的方式,應該可以提升自動跑的效率。scrapy框架、mongodb之類也可以多研究下。
操作環境:Mac, python 3.5
import requests
import random
import time
import csv
import re
import string
import random
from bs4 import BeautifulSoup
try:
import cookielib
except:
import http.cookiejar as cookielib
#header設置
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Connection': 'keep-alive',
'Host': 'movie.douban.com',
'Referer' : 'https://movie.douban.com/subject/26345137/collections',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36'
}
timeout = random.choice(range(60,180))
#豆瓣評分等級
gradeDic = {
'力薦':5,
'推薦':4,
'還行':3,
'較差':2,
'很差':1
}
#爬取的起始頁:爬取思路是從電影的列表頁開始
movielist = 'https://movie.douban.com/tag/2016'
#第(1)步,讀取電影列表頁,得到回傳的可解析的內容
def get_html(url):
while True:
try:
rep = requests.get(url,headers=headers,timeout=timeout)
print(rep)
break
except:
print(url,"頁面訪問失敗")
return rep.text
# 在電影列表頁,獲取每個電影的link,放在temp這個list里面
def get_movie(html):
url_list = []
bs4 = BeautifulSoup(html,"html.parser").body.find(class_='article')#電影列表區
nextUrl = BeautifulSoup(html, "html.parser").body.find(class_='paginator').find(class_='next').find('a').get('href') # 找到下一頁url
movie_list = bs4.find_all(class_='item')
temp = []
for movie in movie_list:
movie_href = movie.find(class_= "pl2").find("a").get("href")
temp.append(movie_href)
return temp
#解析電影詳情頁
def get_data(html):
final = []
bs4 = BeautifulSoup(html,"html.parser").body.find(class_='mod-bd') #找到評論區
movie_href = BeautifulSoup(html,"html.parser").body.find(class_='aside').find(class_ = 'pl2').find('a').get("href")#找到邊欄區
comment_lists = bs4.find_all(class_='comment-item')
for comment in comment_lists:
temp = []
grade = comment.find(class_= re.compile("allstar"))
#有些評分為空,忽略
if grade is None:
pass
else:
rating = grade.get('title') #獲得評價
username = comment.find(class_="avatar").find('a').get('title') #獲得用戶名
datacid = comment.get('data-cid') #評論編號
num_rating = gradeDic[rating] #評價對應的評分
usefulness = comment.find(class_='votes').get_text() #用戶給的是否有用評價
words = comment.find(class_='comment').find('p').get_text().strip() #評論的具體內容
if (rating is None) or (username is None) or (datacid is None) or (words is None): #如果任何一項為空,都pass
pass
else:
temp.extend((username, datacid, rating, num_rating, usefulness, words, movie_href))
final.append(temp) #添加到[]中
return final
#翻頁設置,在評論區翻頁
def turn_page(temp):
#第(1)步里面爬取的頁面上,有20個電影;出于爬取限制,可以寫成for url in temp[0:10],先爬取一部分
for url in temp:
count = 0
currentUrl = url + 'comments?&status=P' #通過觀察,獲取評論區首頁的url
while currentUrl is not None and count < 9: #出于限制設置爬取頁面<10,超過第10頁就會要求登錄
print (currentUrl)
html = get_html(currentUrl) #解析頁面
bs4 = BeautifulSoup(html, "html.parser").body.find(class_='mod-bd') # 找到評論區
nextUrl = BeautifulSoup(html, "html.parser").body.find(id='paginator').find(class_='next').get(
'href') # 找到下一頁url
next_Url = url + 'comments' + nextUrl #下一頁的url
data = get_data(html) #獲取需要爬取的字段
currentUrl = next_Url
count += 1
print(count)
write_data(data, "1.csv") #寫入csv文件
time.sleep(random.choice(range(1, 5)))
#寫入文件
def write_data(data, name):
file_name = name
with open(file_name, 'a', errors='ignore', newline='', encoding='utf-8-sig') as f: #如果是windows,貌似不用寫encoding='utf-9-sig'
f_csv = csv.writer(f)
f_csv.writerows(data)
movie_html = movie_page_html(movielist)
movie_temp = get_movie(movie_html)
turn_page(movie_temp)