查看原文
其他

手把手教你爬豆瓣Top250的电影(二)

徐露露 Stata and Python数据分析 2022-03-15

爬虫俱乐部之前推出的线下培训,得到了各位老师的一致好评。为了更加方便大家学习,满足更多Stata用户的学习需求,爬虫俱乐部已隆重推出在线直播课程,请大家奔走相告!课程报名链接:https://ke.qq.com/course/286526#tuin=9735fd2d,详情见推文《爬虫俱乐部隆重推出网上直播课程第一季》

有问题,不要怕!点击推文底部“阅读原文”下载爬虫俱乐部用户问题登记表并按要求填写后发送至邮箱statatraining@163.com,我们会及时为您解答哟~

喜大普奔~爬虫俱乐部的github主站正式上线了!我们的网站地址是:https://stata-club.github.io,粉丝们可以通过该网站访问过去的推文哟~

好消息:爬虫俱乐部即将推出研究助理供需平台,如果您需要招聘研究助理(Research Assistant or Research Associate),可以将您的需求通过我们的公众号发布;如果您想成为一个RA,可以将您的简历发给我们,进入我们的研究助理数据库。帮我们写优质的推文可以提升您被知名教授雇用的胜算呀!


在上一次的介绍中,通过这两个函数getHTMLText()allurl()我们就可以将所有的网页源代码爬取下来(手把手教你爬豆瓣Top250的电影),本篇推文将介绍我们如何使用re模块处理已经得到的网页源代码。并整理出最终的csv数据文件。

提取网页中符合我们要求的数据信息(getFilmInfo(url))

这是这次爬虫最重要的一部分。对于r.text源码有两种通常的处理方法,一种是使用html解析引擎解析,如BeautifulSoup,一种是使用正则表达式匹配文本。本文使用正则表达式来提取关键信息。正则表达式的优势在于不需要你知道这个源代码的结构,只需要找到相关信息前后的唯一标签即可,大大方便了操作。

同样以Top250的第一页为例。我们将第一页的源代码信息储存到html变量中。

html = getHTMLText(url)

通过检查源代码,我们可以发现,所有的电影名称都保存在<span>…</span>这个标签中。

tlt = re.findall(r'<span>.*?</span>', html)

findall表示以列表的形式返回全部能够匹配到的字符串,得到的列表为:

可是我们发现,我们把电影的其他名称也爬取下来了,可是我们想要的只有中文的电影名,通过观察,那些我们不需要的电影名的前面都有“&nbsp;”,于是我们通过[^&]排除掉它们,程序改为为:tlt = re.findall(r'<span>[^&].*?</span>', html),结果为:

同理得到评分和投票人数:

rating = re.findall(r'<span property="v:average">[\d\.]*</span>', html) voting = re.findall(r'<span>[\d]+人评价</span>', html)

当然这并不是我们想过要的最终结果,我们还得剔除掉尖括号和其中的内容,保留电影名。

for i in range(len(tlt)):      tlt[i] = re.sub(r'<.*?>', '', tlt[i])      rating[i] = re.sub(r'<.*?>', '', rating[i])      voting[i] = re.sub('人评价|<.*?>', '', voting[i])

由于re.findall返回的是列表形式,我们就可以通过一个遍历的方法,使用sub将所有尖括号和其中的内容替换为空。

得到的结果为:

我们使用字典的方法,将三个列表的信息储存到data中,data = {'title': tlt, 'rate': rating, 'votes': voting},即:

将信息储存到字典中之后,我们就可以通过pandas中的DataFrame构建一个表格型数据结构,frame = DataFrame(data, columns=['title', 'rate', 'votes']),得到:

将这些步骤封装成一个函数,即:

def getFilmInfo(url):        html = getHTMLText(url)        tlt = re.findall(r'<span>[^&].*?</span>', html)        rating = re.findall(r'<span property="v:average">[\d\.]*</span>', html)        voting = re.findall(r'<span>[\d]+人评价</span>', html)        
       for
i in range(len(tlt)):               tlt[i] = re.sub(r'<.*?>', '', tlt[i])               rating[i] = re.sub(r'<.*?>', '', rating[i])               voting[i] = re.sub('人评价|<.*?>', '', voting[i])       data = {'title': tlt, 'rate': rating, 'votes': voting}       frame = DataFrame(data, columns=['title', 'rate', 'votes'])      
      return
frame

将三个函数整合成一个函数(main(filename))

将三个函数整合成一个函数(main(filename))

首先创建一个同类型的空的DataFrame名为all,以便在后续的循环添加内容。

df = {'title':[],'rate':[],'votes':[]} all = DataFrame(df)

对每个网页都通过getHTMLText(url)的方法得到源代码,对每个源代码都通过getFilmInfo(url)的方法获得frame

for url in allurl():           getHTMLText(url)           frame = getFilmInfo(url)           all = pd.concat([all,frame])

concat是一个简单的拼接工具。

 仔细观察就会发现前面的索引依旧是原来的,我们可以使用ignore_index=True,它表示不保留连接轴上的索引,产生一组新索引range(total_length)

我们确实将所有的信息都爬取下来了。当然我们还得把爬取下来的数据保存成一个文件。

all.to_csv('e:/film.csv', sep=',', header=True, index=True,encoding='gbk')


最后将其封装成一个函数main(filename)

os.chdir('e:/') #设置默认路径
def main(filename):     df = {'title':[],'rate':[],'votes':[]}     all = DataFrame(df)
    for url in allurl():         getHTMLText(url)         frame = getFilmInfo(url)         all = pd.concat([all,frame],axis=0,ignore_index=True)         all.to_csv(filename, sep=',', header=True, index=True,encoding='gbk')

我们就可以将数据保存到e盘路径下的film.csv文件中。

这样我们的最终的任务就完成啦,是不是很有成就感~。

 

最终附上完整的程序:

import requests
import
re
import
pandas as pd
from pandas import DataFrame import os os.chdir('e:/')
#得到所有的网页链接

def allurl():
      html = []
      for i in range(10):              url = 'https://movie.douban.com/top250?start='+str(i*25)+'&filter='              html.append(url)
      return html
#获取每个链接的源代码

def getHTMLText(url):
   try:          r = requests.get(url,timeout = 30)          return r.text
   except:           print("获取网页失败")
#提取链接中的信息

def getFilmInfo(url):
    html = getHTMLText(url)     tlt = re.findall(r'<span>[^&].*?</span>', html)     rating = re.findall(r'<span property="v:average">[\d\.]*</span>', html)     voting = re.findall(r'<span>[\d]+人评价</span>', html)
    for i in range(len(tlt)):            tlt[i] = re.sub(r'<.*?>', '', tlt[i])            rating[i] = re.sub(r'<.*?>', '', rating[i])            voting[i] = re.sub('人评价|<.*?>', '', voting[i])     data = {'title': tlt, 'rate': rating, 'votes': voting}     frame = DataFrame(data, columns=['title', 'rate', 'votes'])
    return frame
#将三个函数封装成一个函数

def main(filename):
   df = {'title':[],'rate':[],'votes':[]}    all = DataFrame(df)
   for url in allurl():            getHTMLText(url)            frame = getFilmInfo(url)            all = pd.concat([all,frame],ignore_index=True)    all.to_csv(filename, sep=',', header=True, index=True,encoding='gbk')


注:此推文中的图片及封面(除操作部分的)均来源于网络!如有雷同,纯属巧合!

以上就是今天给大家分享的内容了,说得好就赏个铜板呗!有钱的捧个钱场,有人的捧个人场~。另外,我们开通了苹果手机打赏通道,只要扫描下方的二维码,就可以打赏啦!

应广大粉丝要求,爬虫俱乐部的推文公众号打赏功能可以开发票啦,累计打赏超过1000元我们即可给您开具发票,发票类别为“咨询费”。用心做事,只为做您更贴心的小爬虫。第一批发票已经寄到各位小主的手中,大家快来给小爬虫打赏呀~


                                   



             文字编辑:赵宇亮

  技术总编:刘贝贝



往期推文推荐:

1.爬虫俱乐部新版块--和我们一起学习Python

2.hello,MySQL--Stata连接MySQL数据库

3.hello,MySQL--odbcload读取MySQL数据

4.再爬俱乐部网站,推文目录大放送!

5.用Stata生成二维码—我的心思你来扫

6.Hello,MySQL-odbc exec查询与更新

7.Python第一天

8.Python第二天

9.事件研究大放送

10.爬虫俱乐部隆重推出网上直播课程第一季




关于我们

微信公众号“爬虫俱乐部”分享实用的stata命令,欢迎转载、打赏。爬虫俱乐部是由李春涛教授领导下的研究生及本科生组成的大数据分析和数据挖掘团队。

此外,欢迎大家踊跃投稿,介绍一些关于stata的数据处理和分析技巧。

投稿邮箱:statatraining@163.com

投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿”+“推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到关于stata分析数据的问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存