• 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'ttd{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         
  • 相关阅读:
    Servlet-RequestDispatcher.forward方法
    Servlet---RequestDispatcher.include方法
    解决用了vertical-align: middle,但是文字图片依旧不居中的问题
    vue项目中rem适配问题
    微信小程序之使用ecarts---详细步骤
    微信公众号之input输入框获取焦点后,底部固定定位的按钮顶起问题解决办法
    微信公众号开发之解决IOS点击input 、textarea页面错位的问题
    微信小程序用navigationStyle自定义导航栏做法
    微信小程序 mpvue + picker
    PyCharm怎么整理(格式化)当前代码
  • 原文地址:https://www.cnblogs.com/PistonType/p/5498963.html
Copyright © 2020-2023  润新知