1-1 用Python爬取豆瓣及IMDB上的電影信息


下面的代碼可以抓取豆瓣及IMDB上的電影信息,由於每段代碼使用的數據源自上一段代碼輸出的數據,所以需要按順序執行。

step1_getDoubanMovies.py

 

 1 # -*- coding: utf-8 -*-
 2 '''
 3 該腳本得到豆瓣上所有電影的如下信息:
 4 "rate": "7.5",
 5 "cover_x": 2000,
 6 "is_beetle_subject": false,
 7 "title": "鬼鄉",
 8 "url": "https://movie.douban.com/subject/26322928/",
 9 "playable": false,
10 "cover": "https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2226663805.jpg",
11 "id": "26322928",
12 "cover_y": 2820,
13 "is_new": false
14 並保存為csv格式和js格式,但是未去重
15 '''
16 import requests    #此處采用requests方法得到網頁響應
17 import json
18 import time
19 from pandas import DataFrame
20     
21 def getTagData(tag):
22     data_oneTag=[]    #待添加數據列表
23     page_start=0    #起始頁
24     data_oneSubject=[1]    #為了冷啟動,使data_oneSubject不為空
25     #設置代理
26     #proxies={ "http": "http://115.159.96.136:1080"}
27     #設置User-Agent
28     headers={"User-Agent":'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'}
29     #當data_oneSubject不為空,也就是始終可以從網頁中獲取內容時,不停循環    
30     while(data_oneSubject!=[]):
31         #通過修改tag和page_start來不斷的修改網址
32         url='https://movie.douban.com/j/search_subjects?type=movie&tag='+tag+'&sort=recommend&page_limit=20&page_start='+str(page_start)
33         resp=requests.get(url,headers=headers)
34         #resp=requests.get(url,proxies=proxies,headers=headers)  #發出獲取內容請求,得到的resp.text為json字符串
35         data_oneSubject=json.loads(resp.text)  #將json字符串resp.text轉換成Python形式,得到的data_oneSubject整體為一個鍵為'subjects'的長度為1的字典
36         data_oneSubject=data_oneSubject['subjects']   #取出data_oneSubject字典中鍵'subjects'對應的值,為20個字典
37         data_oneTag+=data_oneSubject    #將data_oneSubject添加到data_oneTag數據中
38         page_start+=20  #起始頁增加20
39         time.sleep(1)    #為了避免請求的太頻繁被封掉IP,所以每次循環都要暫停一秒
40     return data_oneTag    #返回標簽為tag時所有獲得的數據
41 
42 data_allTag=[]    #待添加所有標簽的數據集列表
43 moviesNum=0    #所有標簽下的電影總數,該數字沒有消除重復項
44 for tag in ['熱門','最新','經典','可播放','豆瓣高分','冷門佳片','華語','歐美','韓國','日本','動作','喜劇','愛情','科幻','懸疑','恐怖','治愈']:
45     data_oneTag=getTagData(tag)   #針對每個標簽調用getTagData函數  
46     data_allTag+=data_oneTag    #將每個標簽下的得到的數據加入到data_allTag數據集中,最終的data_allTag為數據list數據結構,每一項為一個字典
47     moviesNum+=len(data_oneTag)     #計算所有標簽下電影的總數(包含重復項)
48     print tag+':',len(data_oneTag)    #打印出各個標簽下得到的電影數
49 
50 print '電影總數為:',moviesNum #打印出總電影數,該數字沒有消除重復項
51 for i in range(5):
52     print data_allTag[i]['title']+' '+data_allTag[i]['rate']    #打印出data_allTag的前10項,只輸出鍵'title'和'rate'對應的值
53 
54 df=DataFrame(data_allTag)
55 
56 #title列為unicode編碼格式,在將數據輸出為csv格式時會出現編碼問題,所以下面三行將title列數據轉換為utf-8格式
57 title=df['title']
58 title=title.map(lambda x:x.encode('utf-8'))
59 df['title']=title
60 
61 #將結果中rate列的數字轉換為float格式
62 rate=df['rate']   #將df的rate列取出,格式為Series
63 rate=rate.map(float)    #將rate列中的數值轉換為float格式
64 df['rate']=rate    #將df中的rate列替換為float格式的rate列
65 
66 #將DataFrame格式的結果數據寫入csv格式的文件中
67 df.to_csv('doubanMovies.csv',index=False,header=True)
68 
69 # #將數據結構為list的data_allTag轉換成json格式后保存到doubanMovie.js文件中
70 # try:
71 #     f1=open('doubanMovies.js','w')
72 #     f1.write(json.dumps(data_allTag))    #將list數據結構的data_allTag寫入json文件
73 # except:
74 #     print '寫入js文件未成功!'
75 # finally:
76 #     f1.close()    #注意關閉文件流

 

step2_getScore.py

 1 # -*- coding: utf-8 -*-
 2 '''
 3 該腳本利用step1_doubanMovies.py腳本中得到的csv格式文件進行處理
 4 對豆瓣電影進行了去重
 5 並由rate列得到了score列
 6 '''
 7 import pandas as pd
 8 df=pd.read_csv('doubanMovies.csv')
 9 movies_unique=df.drop_duplicates()    #去重
10 movies_unique.to_csv('doubanMovies_unique.csv',index=False,header=True)    #將最終的數據輸出
11 print len(movies_unique)
12 
13 def getScore(i):
14     if i>=0 and i<6.0:
15         return 0
16     elif i>=6.0 and i<6.5:
17         return 1
18     elif i>=6.5 and i<7.0:
19         return 2
20     elif i>=7.0 and i<7.5:
21         return 3
22     elif i>=7.5 and i<8.0:
23         return 4
24     elif i>=8.0 and i<=10.0:
25         return 5
26     else: 
27         return None
28 
29 rate=movies_unique['rate']    #取出rate列
30 score=rate.map(getScore)   #對rate列應用getScore函數,得到score列
31 movies_unique['score']=score    #將score列添加到movies_unique
32 movies_unique.to_csv('doubanMovies_score.csv',index=False,header=True)    #將最終的數據輸出

step3_getInfoOfOneMovie.py

 

 1 # -*- coding: utf-8 -*-
 2 '''
 3 該段代碼通過step2_getScore.py得到的doubanMovies_score.csv文件中的每個豆瓣電影的網址
 4 獲取每個豆瓣電影的頁面內容信息
 5 得到directors導演、leadingRoles主演、releaseDate上映日期
 6 alterNames又名、IMDBurl對應的IMDB鏈接等信息
 7 '''
 8 
 9 from getInfoOfOneMovie_functions import *    #從getInfoOfOneMovie_functions腳本中引入自己定義的函數
10 doubanMovies_score=pd.read_csv('doubanMovies_score.csv')
11 allUrls=doubanMovies_score['url']
12 
13 movieInfo=DataFrame({'directors':[],'leadingRoles':[],'releaseDate':[],'alterNames':[],'IMDBurl':[]})
14 csvFileName='doubanMovies_scoreInfoAdded.csv'    #包含豆瓣電影對應的IMDB網址的數據文件
15 errorStartPoint=1  #為了方便做錯誤標記,增加該參數,表示上一次運行到哪部電影出錯
16 unknownError=DataFrame({'directors':['unknownError'],'leadingRoles':['unknownError'],'releaseDate':['unknownError'],'alterNames':['unknownError'],'IMDBurl':['unknownError']})   #出現嚴重錯誤時添加該字符串,為了方便添加,所以使用DataFrame格式
17 for i in range(errorStartPoint-1,len(allUrls)):
18     try:
19         movieInfo=appendOne(movieInfo,str(allUrls[i]))
20         print len(movieInfo)+errorStartPoint-1
21     except:                
22         movieInfo=pd.concat([movieInfo,unknownError])
23         print len(movieInfo)+errorStartPoint-1,'with unknownError added'
24     finally:
25         movieInfo.to_csv(csvFileName, index=False, encoding='utf-8')

 

step4_getIMDBRate.py

 

 1 # -*- coding: utf-8 -*-
 2 '''
 3 該段代碼可以通過step3_getInfoOfOneMovie.py得到的
 4 doubanMovies_scoreInfoAdded.csv文件中的IMDBurl
 5 定位到每個豆瓣電影對應的IMDB鏈接
 6 然后解析IMDB鏈接的內容,得到每個電影在IMDB上的IMDBRate評分
 7 和numOfPeopleWhoRate打分人數
 8 '''
 9 import pandas as pd
10 import urllib2
11 import time
12 import lxml.html
13 from pandas import DataFrame
14 doubanMovie_info=pd.read_csv('doubanMovies_scoreInfoAdded.csv')    #取出數據結構為DataFrame的doubanMovies_info
15 IMDBurl=doubanMovie_info['IMDBurl']    #IMDBurl為一個Series
16 IMDBRateList=[]    #初始化IMDBRateList,就是所有的IMDB評分的一個列表
17 numOfPeopleWhoRateList=[]
18 
19 def getDoc(url):
20     headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'}
21     request = urllib2.Request(url, headers=headers)  # 發送請求
22     response = urllib2.urlopen(request)  # 獲得響應
23     time.sleep(1)
24     content = response.read()  # 獲取網頁內容
25     doc = lxml.html.fromstring(content)  # 可能是將網頁以xml格式解析
26     return doc
27 
28 #函數:獲得IMDB評分
29 def getIMDBRate(doc,oneIMDBurl):
30     #匹配IMDB評分的xpath路徑
31     tempList=doc.xpath('//*[@id="title-overview-widget"]/div[2]/div[2]/div/div[1]/div[1]/div[1]/strong/span/text()')
32     return float(tempList[0])   #返回的是float格式的數據
33 
34 #函數:將類似於'123,456'的字符串轉換為int數據類型123456
35 #因為得到的評分人數的格式為'123,456'
36 def toInt(numWithDot):
37     temp1=numWithDot.split(',')  #首先將字符串以‘,’分割成list
38     temp2=''   #初始化一個字符串
39     for i in range(len(temp1)):    #通過循環,將temp1中的各個元素項合並成一個字符串
40         temp2+=temp1[i]
41     temp2=int(temp2)    #將合並后的數字字符串轉換成int格式
42     return temp2
43 
44 #函數:得到評分人數
45 def getNumOfPeopleWhoRate(doc,oneIMDBurl):
46     #匹配評分人數的xpath路徑
47     tempList=doc.xpath('//*[@id="title-overview-widget"]/div[2]/div[2]/div/div[1]/div[1]/a/span/text()')
48     temp=str(tempList[0])  #得到人數,此時為str數據類型
49     numOfPeopleWhoRate=toInt(temp)  #用前面定義的函數轉換數據為int類型
50     return numOfPeopleWhoRate    #返回int類型的評分人數
51 
52 num=1   #沒有IMDB鏈接的電影個數,用作統計
53 startPoint=1 #為了在出錯時,從錯誤的地方重新開始運行,設置了該錯誤點參數
54 for i in range(startPoint-1,len(IMDBurl)):
55     print i+1    #打印出當前位置,作為標記
56     try:
57         #由於有些電影沒有IMDB鏈接,所以要進行判斷
58         if IMDBurl[i]!='-':    #如果有IMDB鏈接
59             doc=getDoc(IMDBurl[i])    #得到xml格式數據
60             #得到IMDB評分
61             IMDBRate=getIMDBRate(doc,IMDBurl[i])
62             IMDBRateList.append(IMDBRate)    #將得到的IMDB評分加入IMDBRateList中
63             #得到評分人數
64             numOfPeopleWhoRate=getNumOfPeopleWhoRate(doc,IMDBurl[i])
65             numOfPeopleWhoRateList.append(numOfPeopleWhoRate)    #將評分人數加入列表
66         else:    #如果沒有IMDB鏈接,將兩個list列表中都加入'-'表示沒有值
67             print 'Movie:',i+1,'Without IMDBurl,No.',num  #打印出沒有IMDB鏈接的電影相關信息
68             num=num+1    #沒有IMDB鏈接的電影數加1
69             IMDBRateList.append('-')
70             numOfPeopleWhoRateList.append('-')
71     except:    #發生未知錯誤時,將兩個list列表中加入'unknownError',表示出現未知錯誤
72         print 'unknownError happened!'
73         IMDBRateList.append('unknownError')
74         numOfPeopleWhoRateList.append('unknownError')
75     finally:
76         #將兩個list列表轉換成DataFrame格式,方便往csv格式文件中添加
77         IMDBRate=DataFrame({'IMDBRate':IMDBRateList,'numOfPeopleWhoRate':numOfPeopleWhoRateList})   #將IMDBRateList轉換為DataFrame格式,方便加入其他數據中
78         #將DataFrame格式的結果添加到csv格式文件中
79         IMDBRate.to_csv('IMDBRate.csv',index=False,encoding='utf-8')

 

step5_final.py

 

 1 # -*- coding: utf-8 -*-
 2 from pandas import DataFrame
 3 import pandas as pd
 4 
 5 def getScore(i):
 6     if i>=0 and i<6.0:
 7         return 0
 8     elif i>=6.0 and i<6.5:
 9         return 1
10     elif i>=6.5 and i<7.0:
11         return 2
12     elif i>=7.0 and i<7.5:
13         return 3
14     elif i>=7.5 and i<8.0:
15         return 4
16     elif i>=8.0 and i<=10.0:
17         return 5
18     else: 
19         return None
20 ###################################################
21 ##將IMDB評分轉換為5分制
22 #df=pd.read_csv('doubanMovies_IMDB.csv')
23 #score_IMDB=[]
24 #for i in range(len(df)):
25 #    if df.ix[i,'IMDBRate']!='No Rating' and df.ix[i,'IMDBRate']!='-':
26 #        score_IMDB.append(getScore(float(df.ix[i,'IMDBRate'])))
27 #    else:
28 #        score_IMDB.append(df.ix[i,'IMDBRate'])
29 #        
30 #df['score_IMDB']=score_IMDB
31 #df.to_csv('doubanMovies_IMDBScore.csv')
32 ###################################################
33 
34 ############################################################################
35 #將豆瓣和IMDB的rate合並,並配置權重
36 #如果沒有相應的IMDB鏈接,或者有IMDB鏈接,但是沒有評分
37 #則合並后的rate就采用豆瓣的rate
38 #最后將合並后的rate轉化為5分制
39 df=pd.read_csv('doubanMovies_IMDBScore.csv')
40 weight_douban=0.5    #豆瓣的rate的權重值
41 weight_IMDB=1-weight_douban    #IMDB的rate的權重值
42 rate_doubanAndIMDB=[]   #初始化合並后的rate列表
43 score_final=[]    #初始化最終的評分列表
44 
45 #得到豆瓣rate和IMDBRate加權后rate_doubanAndIMDB列表
46 for i in range(len(df)):
47     df.ix[i,'rate']=float(df.ix[i,'rate'])    #為防止出錯,再加這么一句 
48     if df.ix[i,'IMDBRate']!='No Rating' and df.ix[i,'IMDBRate']!='-':
49         df.ix[i,'IMDBRate']=float(df.ix[i,'IMDBRate'])    #將數據集中的IMDBRate數據轉換為float格式 
50         #將rate和IMDBRate進行加權        
51         temp=weight_douban*(df.ix[i,'rate'])+weight_IMDB*(df.ix[i,'IMDBRate'])
52         #將加權后的rate值加入到 rate_doubanAndIMDB列表中       
53         rate_doubanAndIMDB.append(temp)
54     else:
55         #如果沒有IMDB鏈接或IMDB沒有評分,則直接使用豆瓣的rate值
56         rate_doubanAndIMDB.append(df.ix[i,'rate'])
57 
58 #利用加權后的rate值得到最終的分數值score_final列表
59 for i in range(len(df)):
60     score_final.append(getScore(rate_doubanAndIMDB[i]))
61      
62 df['rate_doubanAndIMDB']=rate_doubanAndIMDB
63 df['score_final']=score_final
64 df.to_csv('test.csv',index=False)
65 ############################################################################

 

getInfoOfOneMovie_functions.py

 

  1 #-*- coding:utf-8 -*-
  2 '''
  3 該段代碼定義了若干getInfoOfOneMovie.py中用到的函數
  4 前面6個函數都在第7個函數也就是appendOne中調用
  5 '''
  6 import lxml.html
  7 import time
  8 from pandas import DataFrame
  9 import urllib2
 10 import pandas as pd
 11 import re
 12 
 13 #得到網頁的xml格式數據內容
 14 def getDoc(url_oneMovie):
 15     headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'}
 16     request = urllib2.Request(url_oneMovie, headers=headers)  # 發送請求 
 17     response = urllib2.urlopen(request)  # 獲得響應 
 18     time.sleep(1) 
 19     content = response.read()  # 獲取網頁內容  
 20     doc = lxml.html.fromstring(content)  # 可能是將網頁以xml格式解析 
 21     return doc
 22     
 23 #通過xml數據得到導演信息
 24 def getDirectors(doc,url_oneMovie):
 25     directors=doc.xpath('//*[@id="info"]/span[1]/span[2]/a/text()')
 26     #將列表中的每一項先轉換成unicode,再轉換成utf-8格式    
 27     for i in range(len(directors)):
 28         directors[i]=unicode(directors[i]).encode('utf-8') 
 29     return directors  #返回的是list
 30     
 31 #通過xml數據得到主演信息
 32 def getLeadingRoles(doc,url_oneMovie):
 33     leadingRoles=doc.xpath('//*[@id="info"]/span[3]/span[2]/a/text()')
 34     #有些有些豆瓣電影信息里沒有編劇這一項,所以主演會在第二條信息里。
 35     #所以需要判斷得到的主演列表是否為空
 36     #將列表中的每一項先轉換成unicode,再轉換成utf-8格式
 37     if leadingRoles==[]:
 38         leadingRoles=doc.xpath('//*[@id="info"]/span[2]/span[2]/a/text()')
 39     for i in range(len(leadingRoles)):
 40         leadingRoles[i]=unicode(leadingRoles[i]).encode('utf-8')    
 41     return leadingRoles  #返回的是list
 42 
 43 #通過xml數據得到上映日期信息
 44 def getReleaseDate(doc,url_oneMovie):
 45     releaseDate=doc.xpath('//*[@id="info"]/span/text()')   #得到的是一個list,其中有一個元素是上映日期
 46     #將列表中的每一項先轉換成unicode,再轉換成utf-8格式    
 47     for i in range(len(releaseDate)):
 48         releaseDate[i]=unicode(releaseDate[i]).encode('utf-8') 
 49     temp=re.compile(r'\d*-\d*-\d*')
 50     for i in range(len(releaseDate)):
 51         if re.findall(temp,releaseDate[i])!=[]:  #findall返回的是能匹配到的list,所以用是否為[]進行判斷
 52             return releaseDate[i] #返回的是str
 53 
 54 #通過xml數據得到又名信息
 55 def getAlterNames(doc,url_oneMovie):
 56     tempList=doc.xpath('//*[@id="info"]/text()')  #得到的是一個list,最后一個非空的元素就是又名
 57     #將列表中的每一項先轉換成unicode,再轉換成utf-8格式    
 58     for i in range(len(tempList)):
 59         tempList[i]=unicode(tempList[i]).encode('utf-8') 
 60     #取出‘又名’的名字字符串  
 61     temp=re.compile(r'\S')     #匹配非空字符串的正則表達式
 62     for i in range(len(tempList)):     #取出非空字符串,最后一個才是‘又名’
 63         if re.findall(temp,tempList[i])!=[]:  #如果匹配的結果非空
 64             alterNames=tempList[i]    #由於不停的循環,找到的最后一個非空的字符串才是’又名‘
 65     return alterNames    #返回‘又名’,格式為str
 66 
 67 #通過xml數據得到IMDB鏈接信息
 68 def getIMDBurl(doc,url_oneMovie):
 69     xpathList=doc.xpath('//*[@id="info"]/a/text()')
 70     #將列表中的每一項先轉換成unicode,再轉換成utf-8格式    
 71     #有些豆瓣電影沒有對應的IMDB網址,所以要判斷一下是否為[] 
 72     if xpathList!=[]:
 73         for i in range(len(xpathList)):
 74             xpathList[i]=unicode(xpathList[i]).encode('utf-8')     
 75         #取出通過//*[@id="info"]/a得到的形如‘tt12345678’的IMDBurl的ID
 76         #有三種情況:
 77         #1、xpathList長度為1,第一項為tt12345678
 78         #2、xpathList長度為1,第一項為豆瓣內容專題
 79         #3、xpathList長度為2,第二項為tt12345678
 80         #此處采用正則表達式    
 81         temp=re.compile(r'tt\d{3,}')
 82         for i in range(len(xpathList)):
 83             tempList=re.findall(temp,xpathList[i])
 84             if tempList!=[]:
 85                 IMDBurlID=tempList[0]    #得到形如‘tt12345678’的IMDBurl的ID或者None
 86         IMDBurl='http://www.imdb.com/title/' + IMDBurlID + '/'  #將ID轉換成IMDB網址
 87         return IMDBurl    #返回IMDB網址
 88     else:
 89         return '-'
 90         
 91 def appendOne(movieInfo,url_oneMovie):
 92     doc=getDoc(url_oneMovie)
 93     directors=getDirectors(doc,url_oneMovie) #得到的是若干導演的一個list
 94     leadingRoles=getLeadingRoles(doc,url_oneMovie) #得到的是若干主演的一個list
 95     releaseDate=getReleaseDate(doc,url_oneMovie)  #得到的是str字符串
 96     alterNames=getAlterNames(doc,url_oneMovie)   #得到的是str字符串
 97     IMDBurl=getIMDBurl(doc,url_oneMovie)        #得到的str格式的IMDB網址
 98     tempDf=DataFrame({'directors':[directors],'leadingRoles':[leadingRoles],'releaseDate':[releaseDate],'alterNames':[alterNames],'IMDBurl':[IMDBurl]})
 99     movieInfo=pd.concat([movieInfo,tempDf])
100     return movieInfo
101 
102         

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM