Python 2.7
IDE Pycharm 5.0.3
Firefox 47.0.1
豆瓣電影系列:
- 基礎(chǔ)抓?。ㄏ抻凇岸拱旮叻帧边x項電影及評論)請看↓
Python自定義豆瓣電影種類,排行,點評的爬取與存儲(基礎(chǔ)) - 初級抓?。ㄏ抻凇岸拱觌娪啊钡母鞣N選項,包括“熱門”,“豆瓣高分”等十幾個類別及評論,并打包exe)請看↓
Python自定義豆瓣電影種類,排行,點評的爬取與存儲(初級) - 進(jìn)階抓?。ㄔ诔跫壸ト』A(chǔ)上,套上GUI框架,圖像顯示更加人性化,并打包成exe)請看↓
Python自定義豆瓣電影種類,排行,點評的爬取與存儲(進(jìn)階上) - 在進(jìn)階上的基礎(chǔ)上新增TV選項及相應(yīng)功能,新增TOP10 M&T 請看↓
Python自定義豆瓣電影種類,排行,點評的爬取與存儲(進(jìn)階下)
更新說明
1.新增CMD版本,并打包處理
2.新增存入word操作。
3.新增預(yù)告片鏈接,新增推薦相關(guān)電影。
4.自由度加強(qiáng),可自定義對評論,簡介,寫入存儲,推薦,計時(針對cmd版本)等采集開關(guān),采集何種數(shù)據(jù)真正自由選擇。
5.簡化代碼,優(yōu)化代碼結(jié)構(gòu),更加清晰明了富有邏輯(自認(rèn)為)
版本預(yù)覽
GUI版本
CMD版本
總的來說,我優(yōu)化的是cmd版本的,因為gui版本的我實在無力了,好麻煩的,cmd版本的比較適合,python做gui真的不怎么好看,這個gui版本湊合能用,符合更新的功能
效果預(yù)覽
主要就是放cmd效果的了,還有采集后的txt和word存儲
存儲在word中
其中存儲在word中的,我昨晚一直讓他自己跑,大概花了三個小時左右,采集的是全類數(shù)據(jù),也就是加載各類選項等。word中436頁,34W字矚目。。。
CMD版本代碼
# -*- coding: utf-8 -*-
#Author:哈士奇說喵
#爬豆瓣高分電影及hot影評CMD版本1.0
from selenium import webdriver
import selenium.webdriver.support.ui as ui
import time
from docx import Document
def Main(j=1):
class_MT,kind,sort,ask_urls,ask_brief,ask_comments,ask_recommends,number,save_name,save_docx_name,timer = Init()
if timer == 1:start = time.time()
SUMRESOURCES=0
url="https://movie.douban.com/"
print "----------------------------------------------Launch Firefox----------------------------------------------"
driver_item=webdriver.Firefox()
#driver_item=webdriver.Chrome("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe")
wait = ui.WebDriverWait(driver_item,15)
driver_item.get(url)
Write_txt('\\n##########################################################################################','\\n##########################################################################################',save_name)
print "----------------------------------------------Crawling...----------------------------------------------"
##############################################################################
#進(jìn)行網(wǎng)頁get后,先進(jìn)行電影種類選擇的模擬點擊操作,然后再是排序方式的選擇
#最后等待一會,元素都加載完了,才能開始爬電影,不然元素隱藏起來,不能被獲取
#wait.until是等待元素加載完成!
##############################################################################
if class_MT==1:
#選完參數(shù)后,開始爬操作
if save_docx_name != 0:document.add_heading('Movie TOP', 0)
driver_item.get(url)
time.sleep(1) # 更加模擬人類操作,在點擊電影的同是肯定過段時間點擊按照何種排序
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div/div/label[%s]"%kind))
driver_item.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div/div/label[%s]"%kind).click()
time.sleep(1)
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div[3]/div/label[%s]"%sort))
driver_item.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div[3]/div/label[%s]"%sort).click()
num=number+1#比如輸入想看的TOP22,那需要+1在進(jìn)行操作,細(xì)節(jié)問題
#打開幾次“加載更多”保險起見,多開一次加載
num_time = num/20+2
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='list-wp']/div/a[20]"))
for times in range(1,num_time):
driver_item.find_element_by_xpath("http://div[@class='list-wp']/a[@class='more']").click()
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='list-wp']/div/a[%d]"%(20*(times+1))))
#使用wait.until使元素全部加載好能定位之后再操作,相當(dāng)于try/except再套個while把
for i in range(j,num):
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='list']/a[%d]"%num))
list_title=driver_item.find_element_by_xpath("http://div[@class='list']/a[%d]"%i)
print '----------------------------------------------'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------'
moviename = u'電影名: ' + list_title.text
movieurl = u'豆瓣鏈接: ' + list_title.get_attribute('href')
print moviename
print movieurl
#防止頁面出現(xiàn)重復(fù)錯誤,增加迭代修正
while list_title.text==driver_item.find_element_by_xpath("http://div[@class='list']/a[%d]"%(i+20)).text:
print u'遇到頁面加載重復(fù)項bug,開始重新加載...'
j = i
driver_item.quit()
Main(j)
#寫入txt中
if save_name != 0:
Write_txt('\\n------------------------------------------Movies--'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------','',save_name)
Write_txt(moviename.encode('utf-8'),movieurl.encode('utf-8'),save_name)
# 寫入word操作
if save_docx_name != 0:
p = document.add_paragraph('-----------------------------------------------Movies--'+'NO' + str(SUMRESOURCES +1)+'---------------------------------------------------')
p = document.add_paragraph("%s"%(moviename))
p = document.add_paragraph("%s"%(movieurl))
#document.save('demo.docx')
SUMRESOURCES = SUMRESOURCES +1
#獲取具體內(nèi)容和評論。href是每個超鏈接也就是資源單獨的url
try:
getDetails(str(list_title.get_attribute('href')),ask_comments,ask_brief,ask_recommends,ask_urls,save_name,save_docx_name,timer)
except:
print 'can not get the details!'
#爬完數(shù)據(jù)后關(guān)閉瀏覽器,只保留GUI進(jìn)行下一步操作
driver_item.quit()
#選擇電視劇之后的操作,也不知道為什么電視劇按照hot排序一直重復(fù)頁面,只有設(shè)置靜態(tài)等待時間
if class_MT == 2:
#選完參數(shù)后,開始爬操作,選電視劇需要多點擊一次,因為默認(rèn)為電影
driver_item.get(url)
if save_docx_name != 0:document.add_heading('TV TOP', 0)
time.sleep(1)
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='fliter-wp']/h2/a[2]"))
driver_item.find_element_by_xpath("http://div[@class='fliter-wp']/h2/a[2]").click()
time.sleep(1)
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div/div/label[%s]"%kind))
driver_item.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div/div/label[%s]"%kind).click()
time.sleep(1)
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div[3]/div/label[%s]"%sort))
driver_item.find_element_by_xpath("http://div[@class='fliter-wp']/div/form/div[3]/div/label[%s]"%sort).click()
num=number+1#比如輸入想看的TOP22,那需要+1在進(jìn)行操作,細(xì)節(jié)問題
driver_item.find_element_by_xpath(".//*[@id='gallery-frames']/div[1]/div[1]/span[2]/a").click()
driver_item.find_element_by_xpath(".//*[@id='gallery-frames']/div[1]/div[1]/span[1]/a").click()
#打開幾次"加載更多",因為要解決點擊后頁面可能重復(fù)的問題,所以這里多點一次
num_time = num/20+2
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='list-wp']/div/a[20]"))
for times in range(1,num_time):
driver_item.find_element_by_xpath("http://div[@class='list-wp']//a[@class='more']").click()
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='list-wp']/div/a[%d]"%(20*(times+1))))
#使用wait.until使元素全部加載好能定位之后再操作,相當(dāng)于try/except再套個while把
for i in range(j,num):
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='list']/a[%d]"%num))
list_title=driver_item.find_element_by_xpath("http://div[@class='list']/a[%d]"%i)
print '-------------------------------------------TV--'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------'
moviename = u'電視劇名: ' + list_title.text
movieurl = u'豆瓣鏈接: ' + list_title.get_attribute('href')
print moviename
print movieurl
#print unicode碼自動轉(zhuǎn)換為utf-8的
#防止頁面出現(xiàn)重復(fù)錯誤,增加迭代修正
while list_title.text==driver_item.find_element_by_xpath("http://div[@class='list']/a[%d]"%(i+20)).text:
print u'遇到頁面加載重復(fù)項bug,開始重新加載...'
j = i # 從重復(fù)起始項開始加載
driver_item.quit()
Main(j)
if save_docx_name != 0:
p = document.add_paragraph('-----------------------------------------------TV--'+'NO' + str(SUMRESOURCES +1)+'---------------------------------------------------')
p = document.add_paragraph("%s"%(moviename))
p = document.add_paragraph("%s"%(movieurl))
#寫入txt中
if save_name != 0:
Write_txt('\\n----------------------------------------TV--'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------','',save_name)
Write_txt(moviename.encode('utf-8'),movieurl.encode('utf-8'),save_name)
SUMRESOURCES = SUMRESOURCES +1
#獲取具體內(nèi)容和評論。href是每個超鏈接也就是資源單獨的url
try:
getDetails(str(list_title.get_attribute('href')),ask_comments,ask_brief,ask_recommends,ask_urls,save_name,save_docx_name,timer)
except:
print 'can not get the details!'
#爬完數(shù)據(jù)后關(guān)閉瀏覽器,只保留GUI進(jìn)行下一步操作
driver_item.quit()
#本周口碑榜TOP10
if class_MT==3:
#選完參數(shù)后,開始爬操作
driver_item.get(url)
if save_docx_name != 0:document.add_heading('TOP10 M&T', 0)
for i in range(1,11):
wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='billboard-bd']/table/tbody/tr"))
list_title=driver_item.find_element_by_xpath("http://div[@class='billboard-bd']/table/tbody/tr[%d]/td[2]/a"%i)
print '----------------------------------------------'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------'
moviename = u'影視名: ' + list_title.text+' '+getStar(list_title.get_attribute('href'))
movieurl = u'豆瓣鏈接: ' + list_title.get_attribute('href')
print moviename
print movieurl
if save_docx_name != 0:
# 寫入word操作
p = document.add_paragraph('----------------------------------------------WeekTOP--'+'NO' + str(SUMRESOURCES +1)+'--------------------------------------------------')
p = document.add_paragraph("%s"%(moviename))
p = document.add_paragraph("%s"%(movieurl))
#寫入txt中
if save_name != 0:
Write_txt('\\n------------------------------------------WeekTOP--'+'NO' + str(SUMRESOURCES +1)+'----------------------------------------------','',save_name)
Write_txt(moviename.encode('utf-8'),movieurl.encode('utf-8'),save_name)
SUMRESOURCES = SUMRESOURCES +1
#獲取具體內(nèi)容和評論。href是每個超鏈接也就是資源單獨的url
try:
getDetails(str(list_title.get_attribute('href')),ask_comments,ask_brief,ask_recommends,ask_urls,save_name,save_docx_name,timer)
except:
print 'can not get the details!'
#爬完數(shù)據(jù)后關(guān)閉瀏覽器,只保留GUI進(jìn)行下一步操作
driver_item.quit()
if timer == 1:
end = time.time()
print "------------------------Done!It Costs About %.2f Seconds-------------------------"%(end-start)
if save_docx_name != 0:document.save(save_docx_name)
##############################################################################
#當(dāng)選擇一部電影后,進(jìn)入這部電影的超鏈接,然后才能獲取
#同時別忽視元素加載的問題
#在加載長評論的時候,注意模擬點擊一次小三角,不然可能會使內(nèi)容隱藏
##############################################################################
def getDetails(url,comments,brief,recommends,needurl,save_name,save_docx_name,timer):
driver_detail = webdriver.PhantomJS(executable_path="phantomjs.exe")
wait1 = ui.WebDriverWait(driver_detail,15)
driver_detail.get(url)
wait1.until(lambda driver: driver.find_element_by_xpath("http://div[@id='link-report']/span"))
drama = driver_detail.find_element_by_xpath("http://div[@id='link-report']/span")
pre_url = driver_detail.find_element_by_xpath("http://div[@id='related-pic']/ul/li/a").get_attribute('href')
# 判斷是否需要預(yù)告片鏈接
if needurl == 1:
pre_urlp = u"預(yù)告片鏈接:"+pre_url
print pre_urlp
if save_docx_name != 0:p = document.add_paragraph("%s"%(pre_urlp))
if save_name != 0:Write_txt(pre_urlp.encode('utf-8'),'',save_name)
# 是否需要加載簡介
if brief == 1:
dramap = u"劇情簡介:"+drama.text
print "----------------------------------------------Synopsis----------------------------------------------"
print drama.text
if save_docx_name != 0:p = document.add_paragraph("%s"%(dramap))
if save_name != 0:Write_txt(dramap.encode('utf-8'),'',save_name)
# 是否加載評論
if comments == 1:
print "--------------------------------------------Hot comments TOP----------------------------------------------"
#加載四個短評
for i in range(1,5):
try:
comments_hot = driver_detail.find_element_by_xpath("http://div[@id='hot-comments']/div[%s]/div/p"%i)
print u"最新熱評:"+comments_hot.text
if save_docx_name != 0:
p = document.add_paragraph("--------------------------Hot comments TOP%d--------------------------"%i)
p = document.add_paragraph(u"最新熱評:%s"%(comments_hot.text))
comments_hot_wr=comments_hot.text.encode('utf-8')
if save_name != 0:
Write_txt("--------------------------------------------Hot comments TOP%d----------------------------------------------"%i,'',save_name)
Write_txt(comments_hot_wr,'',save_name)
except:
print 'can not caught the comments!'
#嘗試加載長評
try:
driver_detail.find_element_by_xpath("http://img[@class='bn-arrow']").click()
#wait.until(lambda driver: driver.find_element_by_xpath("http://div[@class='review-bd']/div[2]/div/div"))
time.sleep(1)
#解決加載長評會提示劇透問題導(dǎo)致無法加載
comments_get = driver_detail.find_element_by_xpath("http://div[@class='review-bd']/div[2]/div")
if comments_get.text.encode('utf-8')=='提示: 這篇影評可能有劇透':
comments_deep=driver_detail.find_element_by_xpath("http://div[@class='review-bd']/div[2]/div[2]")
else:
comments_deep = comments_get
print "--------------------------------------------Long-comments---------------------------------------------"
print u"深度長評:"+comments_deep.text
if save_docx_name != 0:
p = document.add_paragraph("--------------------------------------------Long-comments--------------------------------------------")
p = document.add_paragraph("%s"%(comments_deep.text))
comments_deep_wr=comments_deep.text.encode('utf-8')
if save_name != 0:
Write_txt("--------------------------------------------long-comments---------------------------------------------\\n",'',save_name)
Write_txt(comments_deep_wr,'',save_name)
except:
print 'can not caught the deep_comments!'
if recommends == 1:
print u"------------------------------------------喜歡該片的人還喜歡------------------------------------------"
if save_docx_name != 0:p = document.add_paragraph("------------------------------------------Recommends------------------------------------------")
if save_name != 0:Write_txt("------------------------------------------Recommends------------------------------------------",'',save_name)
for i in range(1,11):
recommand = driver_detail.find_element_by_xpath("http://div[@class='recommendations-bd']/dl[%d]/dd/a"%i)
recommand_name =recommand.text
recommand_url = recommand.get_attribute('href')
star = getStar(recommand_url)
more = u"%s %s : %s"%(recommand_name,star,recommand_url)
print more
if save_docx_name != 0:p = document.add_paragraph("%s"%(more))
if save_name != 0:Write_txt(more.encode('utf-8'),'',save_name)
##############################################################################
#將print輸出的寫入txt中查看,也可以在cmd中查看,換行符是為了美觀
##############################################################################
def Write_txt(text1='',text2='',title='douban.txt'):
with open(title,"a") as f:
for i in text1:
f.write(i)
f.write("\\n")
for j in text2:
f.write(j)
f.write("\\n")
# 自定義了一個單純獲取評分的子函數(shù),用于推薦電影時候把其獲取評分
def getStar(url):
driver_star = webdriver.PhantomJS(executable_path="phantomjs.exe")
wait1 = ui.WebDriverWait(driver_star,15)
try:
driver_star.get(url)
wait1.until(lambda driver: driver.find_element_by_xpath("http://div[@class='rating_self clearfix']"))
star = driver_star.find_element_by_xpath("http://div[@class='rating_self clearfix']/strong").text
return star
except:
return None
def Init():
class_MT = input("---------------Movie or TV---------------\\n1-Movie 2-TV 3-TOP10 M&T\\nPlease Select: ")
if class_MT != 3:
if class_MT == 1:
kind=input("---------------What kind do you like?---------------\\nHot-1 Newest-2 Classics-3\\nPlayable-4 High Scores-5 Wonderful but not popular-6\\nChinese film-7 Hollywood-8 Korea-9\\nJapan-10 Action movies-11 Comedy-12\\n1Love story-13 Science fiction-14 Thriller-15\\nHorror film-16 Cartoon-17\\nPlease Select:")
if class_MT ==2:
kind=input("---------------What kind do you like?---------------\\nHot-1 American TV-2 UK TV-3\\nKorean TV-4 Japanese TV-5 Chinese TV-6\\nTVB-7 Cartoon-8 Variety-9\\nPlease Select:")
sort=input("---------------Sort by what?---------------\\nSort by hot-1 Sort by time-2 Sort by score-3\\nPlease Select:")
number = input("---------------TOP?---------------\\nPlease Select:")
else:
kind = 1
sort = 1
number= 1
ask_urls = input("---------------Need Trailer?---------------\\nNo Trailer_Url-0 I Need Trailer_Url-1\\nPlease Select:")
ask_brief = input("---------------Need Brief?---------------\\nNo Brief-0 I Need Brief-1\\nPlease Select:")
ask_comments = input("---------------Need Review?---------------\\nNo film reviews-0 I like film reviews-1\\nPlease Select:")
ask_recommends = input("---------------Need Recommends?---------------\\nNo Recommends-0 I Need Recommends-1\\nPlease Select:")
save_name=raw_input("---------------How about store?---------------\\nSave name (xx.txt) No thanks-0\\nPlease Select:")
save_docx_name=raw_input("Save docx name (xx.docx) No thanks-0\\nPlease Select:")
timer = input("---------------Want know how much time it cost?---------------\\nStart the timer-1 No thanks-0\\nPlease Select:")
return class_MT,kind,sort,ask_urls,ask_brief,ask_comments,ask_recommends,number,save_name,save_docx_name,timer
if __name__ == '__main__':
print "---------------Made By MrLevo520---------------"
document = Document()
while True:
Main()
contiune = raw_input("---------------Enter 1 To Continue Others To Quit---------------\\nPlease Select:")
if contiune != "1":break
如果不算亂七八糟的注解大概兩百多行把,貌似還是有點多額,不過核心的都有點重復(fù)了,我懶得再寫子函數(shù)了,或許下次再精簡一下代碼
已上傳GUI版本源碼和CMD版本源以及成品exe文件,如有需要可以下載豆瓣自定義抓取2.0版本
寫入Word
上面提供了第三包的下載地址和實例,如果第三方包還不會安裝,請百度安裝。
實例用法比較多,我們大概只需要用到其中的一兩種就可以了,比如添加heading和正文 最簡單的實例如下
from docx import Document # 導(dǎo)入包
document = Document() # 實例化
document.add_heading('Head!', 0) # 添加heading和擺放位置
p = document.add_paragraph("this is a test") # 添加正文
document.save("test.docx") # 存儲文件
大概是這樣的
Q&A
1.出現(xiàn)不能獲取評論的bug,在我昨晚的采集活動中,發(fā)現(xiàn)最后幾個電影都沒有獲取到評論,但是其余的電影獲取沒有問題,應(yīng)該不是代碼問題,截圖測試
坑爹的連簡介都沒有?。?!豆瓣是太懶了么,,,,還是丟了。。。。。我才不會為幾個特例重寫規(guī)則,還好我用try不然卡死在半夜這多不值啊。
2.重復(fù)加載bug幾率太高。在測試過程中,特別是sort by hot的時候,每次幾乎都會出現(xiàn)重復(fù)加載bug,就是點擊加載更多,之后重復(fù)加載了第一頁,這個bug我在以前的文章中嘗試用遞歸重新加載去解決,雖然可以解決,但是重復(fù)加載的bug日益明顯,我在考慮是不是我的策略錯誤,思想的方法要把爬蟲想成人類,人類一般點擊完電影選項后不可能非常快的點擊排序方式的,所以我使用我以前鄙視的靜態(tài)等待一秒的時間,竟然完美解決問題??上部少R!
Pay Attention
關(guān)于采集速度太慢的問題,沒辦法,取決于網(wǎng)速,還有策略,這里用的是動態(tài)爬取的,所以不能用requests和urllib2等靜態(tài)方法,selenium+PhantomJS/Firefox本來就是這個鳥速度,我也無解,不知是我寫法問題還是本身問題
在打包成exe的cmd版本時候,如果需要顯示中文,最好的方法就是在編譯器中的中文是unicode碼的,也就是說,像是這樣
print u"----中文測試----"在IDE下輸出當(dāng)然是自動轉(zhuǎn)化成utf-8輸出的,但是在打包文件時候直接寫utf-8的中文會亂碼的。但是,寫入txt的時候需要encode成utf-8的,而在寫入word中的時候則是直接用unicode碼寫入,具體得可以自己測試。
最后
豆瓣的爬取項目好久沒碰了,今天國慶,一邊看電影一邊把代碼修改下,羞愧的用了"高階"這個標(biāo)題了,暫且用個"高階上"把,以后采用分布式和多線程集群等方法的時候再重寫"高階下"把。
最后的最后
前幾天剛拿到綠盟的實習(xí)offer,還是我很喜歡的數(shù)據(jù)挖掘/機(jī)器學(xué)習(xí)工程師的職位,很開心,雖然自己折騰的時間或許會少一點了,但這都不重要,這本身就是我自己記錄學(xué)習(xí)歷程的博客,如果有人關(guān)注,也很榮幸。
大家國慶快樂咯!
致謝
python docx包下載
python docx實例參考
@MrLevo520--Python自定義豆瓣電影種類,排行,點評的爬取與存儲(基礎(chǔ))
@MrLevo520--Python自定義豆瓣電影種類,排行,點評的爬取與存儲(初級)
@MrLevo520--Python自定義豆瓣電影種類,排行,點評的爬取與存儲(進(jìn)階上)
@MrLevo520--Python自定義豆瓣電影種類,排行,點評的爬取與存儲(進(jìn)階下)