700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 爬虫实战:爬取豆瓣电影 Top-250 到 Excel 表格中

爬虫实战:爬取豆瓣电影 Top-250 到 Excel 表格中

时间:2018-08-23 15:18:23

相关推荐

爬虫实战:爬取豆瓣电影 Top-250 到 Excel 表格中

最近在家无聊自学了python的一些基础知识。后来看到许多朋友都在写爬虫,自己感觉很有意思,也想试一下 >____<

其实本来我是想将数据爬取到excel之后再增加一些数据库操作,然后用flash建立一个网站将数据导入这个网站中实现数据可视化来着… 但!!!当我万分激动地上号我的pycharm,使用pip安装sqlite3之后,发现我的pycharm无法进行SQLite数据库操作,如图:

但是导入模块时,模块名并没有红色下划线,说明导入成功了啊!而且,当我用尝试用 IDLE shell 操作数据库时,试验了下并没有问题,sqlite3模块可用。这就很让人迷惑了哈~~~ 有图有真相:

下图是我用 IDLE shell 建立的数据库文件:

虽然使用 IDLE shell 可以进行 SQLite 数据库常规操作,但 shell 毕竟太过简陋,操作起来对我这种初学者极其极其的不友好!!!所以,我后面数据可视化的想法刚刚出生就被我的 pycharm 一屁股坐死了 … 0.0

**希望路过的大佬帮助小弟指点迷津 >_____<

分割线----------------------------------------------------------------------------------------------------------------------------

好了,下面是我用 shell 写的一个小爬虫(阉割版),仅仅进行了将相关信息爬取到 excel 中的操作。小白操作,大佬勿喷

首先,我们需要导入相关模块:

import re #正则表达式,进行文字匹配from bs4 import BeautifulSoup #网页解析,获取数据import sqlite3 #进行SQLite数据库操作import xlwt#进行excel操作import urllib.request, urllib.error #制定URL,获取网页数据import osimport sys

当然,里面关于数据库的操作我没有用到,先贴在这里等以后搞明白问题出在哪里了再更新

爬取操作主要分为以下三个步骤:

得到一个指定URL网页的内容

爬取网页

保存数据

于是我定义了三个函数分别对这三个功能进行封装,我们一个一个来哈~~~

首先,是得到一个指定URL网页的内容

因为大多数网页并不欢迎爬虫访问自己,因为会占用网站很大的资源。所以,它们都具有反爬机制。但魔高一尺道高一丈,我们也有反反爬策略!!!(手动狗头)

反反爬豆瓣并不难,只要将我们的爬虫伪装成浏览器就好咯。那怎么伪装呢?很简单,将我们python访问器的名字改成浏览器的名字,再有模有样地将浏览器信息一本正经地写入。然后,对于豆瓣来说你就是那个最靓的浏览器!而不是一只讨厌的小虫子(小声bb)

那么接下来的工作就是获取我们的浏览器名以及其他信息了。获取方法并不复杂,只需要两个强大的工具:ctrl-c(复制),ctrl-v(粘贴)

首先我们需要打开我们的浏览器,找到豆瓣Top-250网址 /top250 ,然后打开开发者模式(键盘按下F12),发现一大堆代码

点击 Network ,然后刷新界面(对,就是你经常用的那个刷新!),然后你会发现界面在动,立刻点击红色按钮暂停刷新。找到最前面的那条时间线,就是最前面单条的那条横线,点一下。你会发现出来了一个 top250 的文件,点击那个文件。啥,没太听懂?没事,咱直接上图:

点开 top250 文件后,你又会发现一些新按钮,点击 Headers,然后一直将页面拉到最底,将 User-Agent 那段话复制下来,留着用(成功一半了)

然后我们开始写代码。这是我第一个函数,用来得到一个指定URL网页的内容。得到内容并不难,主要是要破解豆瓣的反爬机制。

我们定义一个 head 变量,将刚才复制的浏览器信息以字典形式写入,注意!!!一定要是字典形式!

head = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}

然后接下来就简单了,直接调用 urllib.request 模块进行基本的网页读取。在以下代码块中req是请求对象,respond是响应对象。前者负责对网页发出访问请求(带着伪装),后者负责接收网页发出的相应(我的个人理解,参考)。请求对象中的 req = urllib.request.Request(url, headers=head) 是对信息进行封装(依旧是我的个人理解,有哪里不对烦请路过的大佬指正,不胜感激)。参数 url 是要访问的网址。最后返回的 html 当然就是获取到的网页内容啦!

为了能够使程序能够自己消化一部分 BUG,这里加入了异常处理(try-except语句)。这样就不至于有时候报出一大堆红色异常(看着挺烦的)甚至直接导致程序崩溃了。

下面贴出第一个函数的完整代码:

#得到一个指定URL网页的内容def askurl(url):html = ''try:head = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}req = urllib.request.Request(url, headers=head)respond = urllib.request.urlopen(req)html = respond.read().decode('utf-8')except urllib.error.HTTPError as e:if hasattr(e, 'code'):print(e.code)if hasattr(e, 'reason'):print(e.reason)return html

然后,我们就要进行第二个操作,爬取网页啦!

这里要用到 bs4 里的 BeautifulSoup 模块,将 html 网页内容转化成一个复杂的树形结构。大家打开豆瓣网页就会发现,每一页只有25个电影信息,如果想要得到250个电影信息的话需要遍历十页。我们上一个函数只是获取了一个网页的内容,那么如何获取多个网页呢?很简单,for循环。

仔细观察我们会发现豆瓣每个页面的网址都是有规律的。比如第一页:/top250,实际上它省略了一些东西,完整网址应该是/top250?start=0 啥?你问我咋发现的??很简单,跳转到下一页比对一下嘛,很容易发现规律的。你会发现第二页就是/top250?start=25,第三页是/top250?start=50…很明显,每一页的网址最后的数字都是上一页最后电影的序号。知道了这些,我们就能用循环来访问10个网址啦(其实网址最后的数字可以是1~250任意一个,大家有兴趣可以试试。我们这里就用25个电影一组进行爬取咯,是不是很好玩很有意思嘿嘿)

for循环:

for i in range(10):url = baseurl + str(i*25) #前面相同的 baseurl 在函数参数传入html = askurl(url) #上一个定义的函数,获取网页内容

在for循环内部,获取网页内容后对每一个网页逐一进行解析。我们用 BeautifulSoup(html, ‘html.parser’)来完成这个工作。前一个参数html是被解析的网页对象,后一个参数是解析器名称,我们用 html.parser 这个解析器进行解析,并将解析结果赋值给 soup 对象。注意,此时 soup 存放的是一整个网页的内容,里面有25个电影的信息。所以我们还需要再嵌套一个循环,将25个电影逐一进行爬取。

#逐一解析数据soup = BeautifulSoup(html, 'html.parser')for item in soup.find_all('div', class_='item'):data = []

我们来理一下思路:250部电影有10页,每页有25个电影,每个电影我们需要爬取8个标签(疯狂套娃)。哦?你问我啥是标签??不急,咱慢慢说

前面提过,BeautifulSoup 模块就是将 html 网页内容转化成一个复杂的树形结构。那么,有哪几种树形结构呢?主要有以下四种:

Tag 标签及其内容

Navigablestring #标签里的内容,字符串

BeautifulSoup #输出整个文档

comment #特殊的Navigablestring,输出的内容不包含注释符号

我们说的标签,一般指的就是Tag。当你打开浏览器的开发者模式后,点击小箭头,然后点击你想定位的内容,就能定位到相关标签。如图:

当你找到你想要定位的内容时,右键点击代码,点击弹出的 Edit as HTML,就能对其进行复制。我们以上图中的电影名标签为例:

<span class="title">肖申克的救赎</span>

其中 span 是标签名,class="title‘’ 是标签属性,‘’肖申克的救赎‘’ 是字符串内容。我们要提取的就是它的字符串内容(当然只是在这个标签中,其他标签中有可能提取属性或标签名)。至于如何提取,这要用到正则表达式的知识。正则表达式就是几个特定符号组合成的简单语法,用于字符串操作。这里不再赘述,自行百度(狗头)

至于我们上个代码块中的 for 循环(如下),soup.find_all(‘div’, class_=‘item’) 函数,就是用来查找所有标签。具体翻译一下就是:查找所有标签名为’div’,属性 class_=‘item’ 的标签,并返回一个列表(在豆瓣网站上定位一下就知道,这个标签下的子标签几乎涵盖了一个电影的全部内容,所以把它拿来用)。因为列表是一个可迭代对象,所以可以直接拿来循环。然后下文中的每个 item 就是一个电影的所有标签。

for item in soup.find_all('div', class_='item'):

我们需要对提取的字符串进行正则表达式语法定义,即设置模板。至于正则表达式语法,自行百度。下面是我进行的模板设置:

#影片详情链接findLink = pile(r'<a href="(.*?)">')#图片链接findImage = pile(r'<img.*?src="(.*?)".*?>', re.S)#评分findRating = pile(r'<span class="rating_num" property="v:average">(.*)</span>')#评价人数findJudge = pile(r'<span>(.*)人评价</span>')#标题findTitle = pile(r'<span class="title">(.*?)</span>')#一句话概述findInq = pile(r'<span class="inq">(.*?)</span>',re.S)#影片相关内容(导演、主演)findBd = pile(r'<p class="">(.*?)</p>', re.S)

然后下面就是用正则表达式进行字符串提取。有时候提取完成后会出现一些奇奇怪怪的我们不想要的符号,用正则表达式或字符串内置的BIF替换掉就好咯。这里没什么可说的

item = str(item) #将每个电影信息转化成字符串,以进行正则表达式操作link = re.findall(findLink, item)[0]image = findImage.findall(item)[0]title = findTitle.findall(item)if len(title)==1:title = [title[0], ' ']rating = findRating.findall(item)[0]judge = findJudge.findall(item)[0]inq = findInq.findall(item)if len(inq)==0:inq = ' 'if len(inq)==1:inq = inq[0]bd = findBd.findall(item)[0]bd = re.sub('<.*?>(\s+)', '', bd)bd = re.sub('\xa0', '',bd)bd = re.sub('/', '',bd)bd = bd.strip()title[1] = title[1].replace('\xa0/\xa0', '')

再然后,将每一个电影信息装入一个列表进行存储。然后再将这个列表作为一个元素装入一个大列表中,进行所有电影的汇总。这个函数的骚操作完成,输出一下提取到的内容:

芜湖!!!

贴出这个函数的完整代码:

#爬取网页def getdata(baseurl):datalist = []for i in range(10):url = baseurl + str(i*25)html = askurl(url)#逐一解析数据soup = BeautifulSoup(html, 'html.parser')for item in soup.find_all('div', class_='item'):data = []item = str(item)link = re.findall(findLink, item)[0]image = findImage.findall(item)[0]title = findTitle.findall(item)if len(title)==1:title = [title[0], ' ']rating = findRating.findall(item)[0]judge = findJudge.findall(item)[0]inq = findInq.findall(item)if len(inq)==0:inq = ' 'if len(inq)==1:inq = inq[0]bd = findBd.findall(item)[0]bd = re.sub('<.*?>(\s+)', '', bd)bd = re.sub('\xa0', '',bd)bd = re.sub('/', '',bd)bd = bd.strip()title[1] = title[1].replace('\xa0/\xa0', '')data.extend([link, image, title[0], title[1], rating, judge, inq, bd])datalist.append(data)return datalist

最后一个函数辣(芜湖,起飞!)

保存数据到 excel 表格中

在这里,我们要用到 xlwt 模块将数据写入excel

book是创建的一个 excel 文件,其中 encoding=‘utf-8’ 是编码格式。sheet 是在这个文件里创建的一个工作表,第一个参数是工作表的名字,第二个参数是规定覆盖式写入(参照文件操作w格式写入)

book = xlwt.Workbook(encoding='utf-8', style_compression=0)#样式压缩效果sheet = book.add_sheet('豆瓣电影 Top-250 详情信息', cell_overwrite_ok=True)#写入时覆盖以前内容

然后在第一行写入各个内容的标题。其中,write()函数有三个参数,前两个是写入表格的位置(行,列),第三个是写入的内容。实质上,excel 表格就是一个巨大的矩阵,每个单元格都有它的坐标,从零开始。

col = ('电影详情链接', '图片链接', '电影中文名', '电影英文名', '豆瓣评分', '评价人数', '一句话概述', '影片相关内容')for i in range(8):sheet.write(0, i, col[i])

接下来就是将之前爬取的数据写入表格,循环即可:

for i in range(250):print('第%d行打印' % (i+1))for j in range(8):sheet.write(i+1, j, datalist[i][j])

最后,文件保存,收工!!!

book.save(savepath)return

下面是这个函数的完整代码:

#保存数据到 excel 表格中def savedata(datalist, savepath):book = xlwt.Workbook(encoding='utf-8', style_compression=0)#样式压缩效果sheet = book.add_sheet('豆瓣电影 Top-250 详情信息', cell_overwrite_ok=True)#写入时覆盖以前内容col = ('电影详情链接', '图片链接', '电影中文名', '电影英文名', '豆瓣评分', '评价人数', '一句话概述', '影片相关内容')for i in range(8):sheet.write(0, i, col[i])for i in range(250):print('第%d行打印' % (i+1))for j in range(8):sheet.write(i+1, j, datalist[i][j])book.save(savepath)return

看一下效果:

哈哈哈哈内心有那么一点小激动

整个程序的完整代码我贴在这里了,运行后你在D盘会发现一个文件叫做:

打开就可以看到电影信息。但你必须提前安装过相关模块,否则会报错。而且,要保证你的电脑有网

安装模块我建议 pip 安装。如果你已经安装过 pip,只需键盘按下 windows+r,然后在弹出框里输入 cmd,在弹出的黑框里输入 pip install [模块名称],然后静静等着就行了。安装完成后如果没法用,重启一下IDLE。

没安装 pip 的在网上自行百度安装,一劳永逸。当然,用 Anaconda 进行安装也是一个很好的选择(我感觉两者差不多…)

不说了,以下是完整代码:

#-*- coding = utf-8 -*-#@Time : /7/22 11:33#@Author : 辉#@File : 爬取豆瓣 TOP-250 电影.py#@Software : IDLE shellimport re #正则表达式,进行文字匹配from bs4 import BeautifulSoup #网页解析,获取数据import sqlite3 #进行SQLite数据库操作import xlwt#进行excel操作import urllib.request, urllib.error #制定URL,获取网页数据import osimport sys#得到一个指定URL网页的内容def askurl(url):html = ''try:head = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'}req = urllib.request.Request(url, headers=head)respond = urllib.request.urlopen(req)#注意括号里不要写成url,犯了两次了html = respond.read().decode('utf-8')except urllib.error.HTTPError as e:if hasattr(e, 'code'):print(e.code)if hasattr(e, 'reason'):print(e.reason)return html#影片详情链接findLink = pile(r'<a href="(.*?)">')#图片链接findImage = pile(r'<img.*?src="(.*?)".*?>', re.S)#评分findRating = pile(r'<span class="rating_num" property="v:average">(.*)</span>')#评价人数findJudge = pile(r'<span>(.*)人评价</span>')#标题findTitle = pile(r'<span class="title">(.*?)</span>')#一句话概述findInq = pile(r'<span class="inq">(.*?)</span>',re.S)#影片相关内容(导演、主演)findBd = pile(r'<p class="">(.*?)</p>', re.S)#爬取网页def getdata(baseurl):datalist = []for i in range(10):url = baseurl + str(i*25)html = askurl(url)#逐一解析数据soup = BeautifulSoup(html, 'html.parser')for item in soup.find_all('div', class_='item'):data = []item = str(item)link = re.findall(findLink, item)[0]image = findImage.findall(item)[0]title = findTitle.findall(item)if len(title)==1:title = [title[0], ' ']rating = findRating.findall(item)[0]judge = findJudge.findall(item)[0]inq = findInq.findall(item)if len(inq)==0:inq = ' 'if len(inq)==1:inq = inq[0]bd = findBd.findall(item)[0]bd = re.sub('<.*?>(\s+)', '', bd)bd = re.sub('\xa0', '',bd)bd = re.sub('/', '',bd)bd = bd.strip()title[1] = title[1].replace('\xa0/\xa0', '')data.extend([link, image, title[0], title[1], rating, judge, inq, bd])datalist.append(data)return datalist#保存数据def savedata(datalist, savepath):book = xlwt.Workbook(encoding='utf-8', style_compression=0)#样式压缩效果sheet = book.add_sheet('豆瓣电影 Top-250 详情信息', cell_overwrite_ok=True)#写入时覆盖以前内容col = ('电影详情链接', '图片链接', '电影中文名', '电影英文名', '豆瓣评分', '评价人数', '一句话概述', '影片相关内容')for i in range(8):sheet.write(0, i, col[i])for i in range(250):print('第%d行打印' % (i+1))for j in range(8):sheet.write(i+1, j, datalist[i][j])book.save(savepath)returndef main():data = getdata('/top250?start=')savedata(data, 'd:\\豆瓣电影 Top-250 详情信息.xls')if __name__ == '__main__':main()

溜了溜了,吃饭去了(手动狗头)

博文不当之处还请路过的大佬批评指正,不胜感激!!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。