2-1 用Python尝试对豆瓣上的演员参演电影的电影名和上映日期进行抓取

时间:2021-07-20 12:22:13

 

 1 step1_actorsDate.py
 2 # -*- coding: utf-8 -*-
 3 import requests
 4 import pandas as pd
 5 import lxml.html
 6 import time
 7 from pandas import DataFrame
 8 
 9 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'}
10 def getDoc(url):
11     resp=requests.get(url,headers=headers)
12     time.sleep(1)
13     content=resp.text
14     doc = lxml.html.fromstring(content)
15     return doc
16 
17 def getactorUrl(doc,url_oneMovie):
18     leadingRoles=doc.xpath('//*[@id="info"]/span[3]/span[2]/a/text()')
19     actorUrl=doc.xpath('//*[@id="info"]/span[3]/span[2]/a/attribute::href')
20     if leadingRoles==[]:
21         leadingRoles=doc.xpath('//*[@id="info"]/span[2]/span[2]/a/text()')
22         actorUrl=doc.xpath('//*[@id="info"]/span[2]/span[2]/a/attribute::href')
23     for i in range(len(leadingRoles)):
24         leadingRoles[i]=unicode(leadingRoles[i]).encode('utf-8')
25     return leadingRoles,actorUrl  #返回的是list
26 
27 leadingRoles=[]
28 actorUrl=[]
29 
30 df=pd.read_csv('doubanIMDB_data_final.csv')
31 urllist=df['url']
32 startPoint=995
33 for i in range(startPoint-1,len(urllist)):
34     try:
35         print i+1
36         url=urllist[i]
37         doc = getDoc(url)
38         temp1,temp2= getactorUrl(doc,url)  #temp1和temp2分别是主演和主演对应的链接
39         leadingRoles=leadingRoles+temp1
40         actorUrl=actorUrl+temp2
41     except:
42         print 'Error'
43     finally:
44         df_actor = DataFrame({'leadingRoles': leadingRoles, 'actorUrl': actorUrl})
45         df_actor.to_csv('test.csv', index=False)

 

 1 step2_getUrl.py
 2 # -*- coding: utf-8 -*-
 3 '''
 4 该脚本的功能仅仅是将actorUrl列中的每一项转化成网页链接
 5 并去重
 6 '''
 7 import pandas as pd
 8 df=pd.read_csv('actors.csv')
 9 print len(df)
10 df.drop_duplicates()  #去重
11 print len(df)
12 for i in range(len(df)):
13     df.ix[i,'actorUrl']='https://movie.douban.com'+df.ix[i,'actorUrl']
14 df.to_csv('actors_unique.csv',index=False)

 

 1 step3_searchToUrl.py
 2 # -*- coding: utf-8 -*-
 3 '''
 4 actorDate.py得到的演员及其对应网站的数据中,有些并不是演员的主页网址,
 5 而是在豆瓣上搜索该演员的页面
 6 该脚本的作用就是通过演员的搜索页面得到该演员的主页网址
 7 '''
 8 import requests
 9 import pandas as pd
10 import lxml.html
11 import time
12 from pandas import DataFrame
13 
14 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'}
15 def getDoc(url):
16     resp=requests.get(url,headers=headers)
17     time.sleep(1)
18     content=resp.text
19     doc = lxml.html.fromstring(content)
20     return doc
21 
22 def searchToUrl(searchPage):
23     doc = getDoc(searchPage)
24     #此处用的是attribute属性,得到的是属性中的href属性
25     temp = doc.xpath('//*[@id="content"]/div/div[1]/div[1]/div/div[2]/h3/a/attribute::href')
26     #如果得不到演员的主页网址,则返回withoutHomePage
27     if temp==[]:
28         temp = ['withoutHomepage']
29     actorUrl = temp[0]
30     return actorUrl
31 
32 df=pd.read_csv('actors_unique.csv')
33 errorNum=0  #统计页面中为搜索页面的个数
34 for i in range(len(df)):
35     temp=df.ix[i,'actorUrl']
36     if 'search' in temp:  #如果网址中含有'search'字样,则说明该网址为豆瓣电影中该演员的搜索页面
37         #需要进行修正,将该搜索页面修改为演员的主页
38         errorNum+=1
39         temp=searchToUrl(temp)  #调用searchToUrl函数,返回的是演员主页
40         print '已修正'+str(errorNum)+'个页面!'  #作为标记
41         print '修改为:',temp  #作为标记
42         df.ix[i,'actorUrl']=temp  #将搜索页修改为演员主页
43 
44 #对修改之后的数据进行错误统计
45 errorNumAfter=0
46 for i in range(len(df)):
47     temp=df.ix[i,'actorUrl']
48     if 'search' in temp:
49         errorNumAfter+=1
50 print '修改后的错误个数为:',errorNumAfter
51 
52 #将修改后的数据输出到文件中
53 df.to_csv('actors_correct.csv',index=False)

 

 1 step4_getWorks.py
 2 # -*- coding: utf-8 -*-
 3 import requests
 4 import time
 5 import lxml.html
 6 import re
 7 from pandas import DataFrame
 8 import pandas as pd
 9 import random
10 
11 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'}
12 proxies={'http':'http://190.195.170:8080'}
13 # cookies = dict(cookies_are='working')
14 # ,cookies=cookies
15 # ,proxies=proxies
16 def getDoc(url):
17     resp=requests.get(url,headers=headers)  #得到网页响应
18     print resp.status_code
19     timegap=random.random()*5
20     time.sleep(timegap)   #暂停1秒,防止抓取太频繁被封IP
21     content=resp.text  #获取相应内容
22     doc = lxml.html.fromstring(content)
23     return doc
24 
25 
26 #函数:将形如(2016)的形式转换成int格式的2016
27 #并返回int格式的2016
28 def toInt(dateOfMoviesList):  #注意处理对象为list列表
29     reYear = re.compile('\((\d*)\)')  #编译待匹配字符串
30     for i in range(len(dateOfMoviesList)):
31         temp=re.findall(reYear,dateOfMoviesList[i])  #对每一项进行匹配
32         if temp!=[]:  #有些演员演过的电影没有标注上映日期,所以需要做非空判断
33             dateOfMoviesList[i]=int(temp[0])
34         else:
35             dateOfMoviesList[i]=99999999
36     return dateOfMoviesList
37 
38 df=pd.read_csv('step3_actors_correct.csv')
39 actorMovies=[]  #初始化演员演过的电影的列表
40 yearOfFirstMovie=[]  #初始化演员出道年份列表,此处将演员演过的最老电影的年份作为他的出道年份
41 moviesNum=[]  #初始化演员演过的电影数的列表
42 errorNum=1  #对出错数进行计数
43 for k in range(1197,len(df)):
44     url_actor=df.ix[k,'actorUrl']  #取出每个演员的主页网址
45     print df.ix[k,'leadingRoles']
46     try:
47         if url_actor!='withoutHomepage':  #由于有些演员没有主页,所以此处进行判断
48             i=0  #用于内层循环
49             temp1=[1]  #冷启动
50             moviesOfActorList=[]  #初始化某一个演员演过电影的列表,每一次循环都要初始化一次
51             dateOfMoviesList=[]  #初始化某一个演员演过电影对应日期的列表,此处是形如'(2016)'的形式
52             while(temp1!=[]):  #当可以抓取到内容时,不停循环
53                 url_moviesOfActor=url_actor+'movies?sortby=time&format=pic&start='+str(i*10)  #根据网址规律得到
54                 doc=getDoc(url_moviesOfActor)
55                 temp1=doc.xpath('//*[@id="content"]/div/div[1]/div[2]/ul/li/dl/dd/h6/a/text()')
56                 moviesOfActorList+=temp1   #将每个页面的得到的电影列表加入到该演员演过电影的列表中
57                 temp2=doc.xpath('//*[@id="content"]/div/div[1]/div[2]/ul/li/dl/dd/h6/span[1]/text()')
58                 dateOfMoviesList+=temp2  #同理
59                 i+=1  #用于内层循环
60             dateOfMoviesList=toInt(dateOfMoviesList)  #调用toInt函数,将得到的年份字符串转换为int数据类型
61             yearOfFirstMovie.append(min(dateOfMoviesList))  #演员出道年份,即演员演过的第一部电影,就是所有该演员演过电影的年份最小的那一个
62             #######################################
63             # 未解决
64             # 对演员演过的电影名字列表进行格式转换
65             # for i in range(len(moviesOfActorList)):
66             #     print moviesOfActorList[i]
67             #######################################
68             temp={'moviesOfActor':moviesOfActorList,'dateOfMovies':dateOfMoviesList}  #将演员演过的电影及电影的日期转换成字典
69             actorMovies.append(temp)  #将上述字典作为一项,不停加入到演员演过的电影列表中
70             moviesNum.append(len(moviesOfActorList))  #将演员演过的电影的数量,不停加入到演员演过的电影数量列表中
71         else:  #如果该演员没有豆瓣主页,则分别向列表中加入下面三项
72             actorMovies.append('withoutHomepage')
73             yearOfFirstMovie.append('unknown')
74             moviesNum.append('unknown')
75     # except:  #如果出错,进行如下处理
76     #     actorMovies.append('error')
77     #     yearOfFirstMovie.append('error')
78     #     moviesNum.append('error')
79     #     print 'error,No.',errorNum
80     #     errorNum+=1  #错误数量统计
81     finally:
82         print k+1  #做标记使用
83         df1=DataFrame({'actorMovies':actorMovies,'yearOfFirstMovie':yearOfFirstMovie,'moviesNum':moviesNum})
84         df1.to_csv('test.csv',index=False)