博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
1-1 用Python爬取豆瓣及IMDB上的电影信息
阅读量:4649 次
发布时间:2019-06-09

本文共 15346 字,大约阅读时间需要 51 分钟。

下面的代码可以抓取豆瓣及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": false14 并保存为csv格式和js格式,但是未去重15 '''16 import requests    #此处采用requests方法得到网页响应17 import json18 import time19 from pandas import DataFrame20     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-Agent28     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 #起始页增加2039 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']=title60 61 #将结果中rate列的数字转换为float格式62 rate=df['rate'] #将df的rate列取出,格式为Series63 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 016     elif i>=6.0 and i<6.5:17         return 118     elif i>=6.5 and i<7.0:19         return 220     elif i>=7.0 and i<7.5:21         return 322     elif i>=7.5 and i<8.0:23         return 424     elif i>=8.0 and i<=10.0:25         return 526     else: 27         return None28 29 rate=movies_unique['rate']    #取出rate列30 score=rate.map(getScore)   #对rate列应用getScore函数,得到score列31 movies_unique['score']=score    #将score列添加到movies_unique32 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-121 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 pd10 import urllib211 import time12 import lxml.html13 from pandas import DataFrame14 doubanMovie_info=pd.read_csv('doubanMovies_scoreInfoAdded.csv')    #取出数据结构为DataFrame的doubanMovies_info15 IMDBurl=doubanMovie_info['IMDBurl']    #IMDBurl为一个Series16 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 doc27 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数据类型12345635 #因为得到的评分人数的格式为'123,456'36 def toInt(numWithDot):37 temp1=numWithDot.split(',') #首先将字符串以‘,’分割成list38 temp2='' #初始化一个字符串39 for i in range(len(temp1)): #通过循环,将temp1中的各个元素项合并成一个字符串40 temp2+=temp1[i]41 temp2=int(temp2) #将合并后的数字字符串转换成int格式42 return temp243 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链接的电影数加169 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 110     elif i>=6.5 and i<7.0:11         return 212     elif i>=7.0 and i<7.5:13         return 314     elif i>=7.5 and i<8.0:15         return 416     elif i>=8.0 and i<=10.0:17         return 518     else: 19         return None20 ###################################################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_IMDB31 #df.to_csv('doubanMovies_IMDBScore.csv')32 ###################################################33 34 ############################################################################35 #将豆瓣和IMDB的rate合并,并配置权重36 #如果没有相应的IMDB链接,或者有IMDB链接,但是没有评分37 #则合并后的rate就采用豆瓣的rate38 #最后将合并后的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_doubanAndIMDB63 df['score_final']=score_final64 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 movieInfo101 102

 

转载于:https://www.cnblogs.com/PistonType/p/5498963.html

你可能感兴趣的文章
LC 711. Number of Distinct Islands II
查看>>
python爬虫从入门到放弃(八)之 Selenium库的使用
查看>>
[LeetCode] Min Stack
查看>>
潭州课堂25班:Ph201805201 django 项目 第二十四课 文章主页 多级评论数据库设计 ,后台代码完成 (课堂笔记)...
查看>>
vi 和vim 的区别
查看>>
FileZilla 安装配置参考
查看>>
添加MD5 密码加密
查看>>
laravel 模块化管理 插件 caffeinated
查看>>
mysql mpm
查看>>
CentOS工作内容(二)关闭SELinux
查看>>
演义江湖玩法汇总
查看>>
IOS中单例的简单使用
查看>>
php array_key_exists() 与 isset() 的区别
查看>>
Springboot @Transactional Mysql事务 无效
查看>>
数组去重的几种方法
查看>>
PHP5.4连接sqlserver
查看>>
kindle读书笔记——2017.05.22-06.21 ...
查看>>
iOS开发总结(A0)- Localization
查看>>
vue-router 跳转原理
查看>>
strncpy函数使用
查看>>