爬蟲之爬取豆瓣電影評論
來自專欄 python學習總結專欄
中秋閑暇,本來想著寫一個小爬蟲,寫著寫著竟然被豆瓣網封IP了,氣傻人也!便買了一個代理,哈哈終究還是爬下來了。
先看一下整體架構吧。
整個項目代碼主要分為3個模塊,分別為,分析電影信息模塊,代理模塊,資料庫模塊。
關於網頁的分析就略去了,因為之前的淘寶bra文章中都已經實現過了。這裡用的和那裡用的是一樣的,就從電影信息模塊開始吧,
先看需要的庫
import requestsimport re #正則庫import random #隨機庫import timefrom lxml import etreeimport jsonfrom databases import SetMysql #自己寫的一個MySQL的資料庫的介麵包from proixy import Proixy #自己寫的一個代理介麵包
電影信息模塊:
在電影信息模塊中有兩部分,分別為,獲取粗略的電影信息,包含電影名稱,豆瓣評分,導演,電影ID,電影詳情頁面URL,電影海報的URL,第二部分,獲取詳細的電影信息,分為:
電影類型,電影國家,電影時長,評論用戶和用戶評論信息
如下代碼:
class Movice_crowl(): def __init__(self): #總頁面,在這個頁面獲取所有的電影URL等信息 self.base_url = https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=電影&start= self.headers = { User-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0 } #設置初始的PROIXY(代理),在爬蟲開始後,每更換一個電影,添加一次重新獲取的代理 self.poxies = [{https: 211.159.171.58:80}, {https: 111.200.239.42:8080}, {https: 124.65.116.170:8080}, {https: 123.119.216.65:61755}] self.mysql = SetMysql()#初始化資料庫介面 def crowl_start(self,page_num): #隨機選擇一個代理 proxy = random.choice(self.poxies) while True: #為了避免由於超時導致的中斷爬蟲,所以添加try try: result = requests.get(self.base_url + str(page_num), headers=self.headers, proxies=proxy) #當返回的code值不等於200時,表示數據返回錯誤。 if result.status_code !=200: proxy = random.choice(self.poxies) else: break except: proxy = random.choice(self.poxies) #將json轉換為字典 infos = json.loads(result.text) #開始分析第一部分電影信息 self.get_movices_info(infos) def get_movices_info(self,info): movice_info = info[data] for movice in movice_info: data = {} name = movice[title] rate = movice[rate] #將列表的內容轉化為字元串 director = ",".join(movice[directors]) url = movice[url] image_url = movice[cover] id = movice[id] data[movice_name] = name data[rate] = rate data[director] = director data[movice_url] = url data[image_url] = image_url data[movice_id] = id print(data[movice_name]) #寫入資料庫 self.mysql.insert_movice_data(data) #開始分析詳細電影信息 self.get_movices_comment(id) def get_movices_comment(self,id): comment_url = https://movie.douban.com/subject/+id+/comments?start=0&limit=20&sort=new_score&status=P while True: #請求詳細URL的返回值,如果不正常則返回狀態值 coments = self.get_url_info(comment_url) #如果為數字,則表示已經出錯 if coments.isdigit(): break html = etree.HTML(coments) movice_id = id movice_in = html.xpath(//div[@class="movie-summary"]/span)[0] movice_name = html.xpath(//div[@id="content"]/h1/text())[0].split( )[0] movice_type =" ".join(movice_in.xpath(./p[3]/text())).strip() movice_country =" ".join(movice_in.xpath(./p[4]/text())).strip() movice_long =" ".join(movice_in.xpath(./p[5]/text())).strip() infos = html.xpath("//div[@id=comments]/div[@class=comment-item]") for info in infos: data = {} coments_user = info.xpath(./div[@class="comment"]/h3/span[@class="comment-info"]/a/text())[0] coments_info = info.xpath(./div[@class="comment"]/p/span/text())[0] #去掉用戶和用戶評論中的特殊字元 coments_user = self.remove_emoji(coments_user) coments_info = self.remove_emoji(coments_info) data[movice_id] = movice_id data[movice_name] = movice_name data[movice_type] = movice_type data[movice_country] = movice_country data[movice_long] = movice_long data[coments_user] = coments_user data[coments_info] = coments_info time.sleep(0.5) #插入資料庫 self.mysql.insert_coments_data(data) #獲取下一頁URL url = html.xpath(//div[@class="center"]/a[@class="next"]/@href)[0] #構造下一跳信息 comment_url =https://movie.douban.com/subject/+id+/comments+url
在上述進行過程中,有幾個介面詳細說明如下:
#獲取詳細信息的URL的介面 def get_url_info(self,url): proxy = random.choice(self.poxies) while True: try: res = requests.get(url=url,headers=self.headers,proxies=proxy) if res.status_code != 200: print(res.status_code) return str(res.status_code) return res.text except: proxy = random.choice(self.poxies) #用著則表達是刪除欄位中特殊字元 def remove_emoji(self, emoji_text): hightpoints = re.compile(u[U00010000-U0010ffff]) text = hightpoints.sub(u, emoji_text) return text 獲取代理IP的介面 def resert_proixy(self): try: self.poxies=self.poxies + Proixy.get_proixy() except: pass
第二部分,MySQL資料庫介面實現
在資料庫介面實現中,主要使用了一個MySQL語句實現的
insert into t2(id,name) values(3,ppp)
代碼如下:
import pymysqlclass SetMysql(): def __init__(self): self.db = pymysql.connect( host = 127.0.0.1, user = root, password = root, database = douban_sql, port = 3306 ) self.cursor = self.db.cursor() def insert_movice_data(self,data): sql = insert into movice_info(id,movice_name,rate,director,movice_id,movice_url,image_url) values(null,%s,%s,%s,%s,%s,%s) self.cursor.execute(sql,(data[movice_name],data[rate],data[director],data[movice_id],data[movice_url],data[image_url])) self.db.commit() def insert_coments_data(self,data): sql = insert into coments_infos(id,movice_id,movice_name,movice_type,movice_country,movice_long,coments_user,coments_info) values(null,%s,%s,%s,%s,%s,%s,%s) self.cursor.execute(sql,(data[movice_id],data[movice_name],data[movice_type],data[movice_country],data[movice_long],data[coments_user],data[coments_info])) self.db.commit() def close_databases(self): self.db.close()
第三部分,代理部分:
在這個部分,我在快代理上購買了一些代理,比較便宜,質量一般,爬的比較慢。
代碼如下:
import requestsclass Proixy(): def __init__(self): self.headers = { User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0 } #該介面為代理的介面 self.url = https://dev.kdlapi.com/api/getproxy/?orderid=xxxxxxx&num=100&area=%E5%8C%97%E4%BA%AC%2C%E4%B8%8A%E6%B5%B7&b_pcff=1&protocol=2&method=2&an_ha=1&sp1=1&dedup=1&sep=1 #請求代理 def get_proixy(self): try: res = requests.get(self.url,headers=self.headers) ppp = [] #對代理返回的數據進行清洗,到達想要的效果 for x in res.text.split(
): y = {} y[https] = x.strip(
) ppp.append(y) #最後以列表包含字典的形式返回 return ppp except: pass
爬取的結果如下:
雖然數據比較慢,但是還是可以下下來的
IP被封了真的很蛋疼,如果要買代理,一定要買好一點的。。。
推薦閱讀: