使用Python实现豆瓣阅读书籍信息的获取

浏览: 3631

最近一直在看Python方面的知识,包括数据分析中常用的numpy、pandas、scipy等模块;数据库API接口,如常见的pymysql、pymssql等模块;爬虫方面所需要的urllib、bs4等模块;还有正则表达式re模块。在之前的几期中我们已经详细介绍了numpy、pandas和pymysql、pymssql模块的应用,具体可参见下文:

Python数据分析之numpy学习(一)

Python数据分析之numpy学习(二)

Python数据分析之pandas学习(一)

Python数据分析之pandas学习(二)

利用Python读取外部数据文件

       今天我们就来讲讲有关爬虫的一点点知识和应用,文章内容相对简单,可操作比较强,后期我也将会更加深入的挖掘Python实现爬虫的方法和应用。接下来我们就以一个例子开始吧。

       豆瓣是我常去的一个网站,上面提供了图书、电影、音乐等方面的推荐、评论和价格比较如果我需要在买一本Python方面的书,我会去豆瓣看看都有哪些被推荐的书,以及这些书的评分、评价等,从而最终确定我该买那本书。下面这幅图就是豆瓣阅读中搜索Python的返回信息:

Clipboard Image.png

 于是我突发奇想,是否可以将自己学习的urllib、bs4和pymysql模块应用于一个简单的爬虫呢?将这些书籍的名称、作者、价格、分类、评分等信息爬取下来,并存放到数据库中。于是我开始动手准备,为完成这个简单的爬虫,我所使用的工具是Python3.5和MySQL5.6。

导入开发所需的模块

In [1]: import urllib

In [2]: from bs4 import BeautifulSoup

In [3]: import pymysql

       我们以url为https://read.douban.com/search?q=Python&start=0为例,实际上我搜出来的有3页,随后通过循环的方式一次性爬取3个页面的内容,这里先以第一页的内容为例,看看如何爬取该页面的内容。

       使用urllib的子模块request中的urlopen方法打开源代码,并使用read方法将源代码读取下来:

In [4]: url = 'https://read.douban.com/search?q=Python&start=0'

In [5]: content = urllib.request.urlopen(url).read()

#打印内容

In [6]: print(content)

Clipboard Image.png

发现一个非常严重的问题:所有的中文都没有能够正常的显示出来!没关系,我们只需要将content的字符集改为utf8即可。

In [7]: content = content.decode('utf-8')

In [8]: print(content)

Clipboard Image.png

哈哈,这会中文都回来了吧~

       接下来我们就使用bs4模块下的BeautifulSoup函数解析上面读取下来的网页内容,并通过prettify的方法将网页内容以嵌套的方式打印出来,显得好看一些。

In [9]: soup = BeautifulSoup(content,'html.parser')

In [10]: print(soup.prettify())

Clipboard Image.png

非常好!接下来就是我该如何截取出我想搜集的字段内容,如书的名称、作者等信息。如果你使用Chrom浏览器的话,你可以通过右击的方式,选择“审查元素”,就可以进入下图所示的页面。具体操作如下:

1)点击搜索图标;

2)选择需要爬取的大块内容,如页面中第一本书的所有信息;

3)回到下方的网页源代码,逐个展开你就会发现具体的类、标签所对应的书本信息,而且最下方也会显示div.info的字样哦。这个字样就是告诉你,这一本书的内容全部包含在class为info的标签里面。

Clipboard Image.png

好了,知道如何获取整本书的class了,接下来就是看每一个所需信息的标签是什么就可以啦。方法类似,你不妨试试~如有问题可以联系我。

       下面我们使用select方法抓取出书本的相关信息,由于这一个页面中,有10本书,所以就需要通过循环的方式把这一页所有书籍的相关信息抓取出来:

In [12]: for content in soup.select('.info'):    #info为大块内容对应的class

    ...:         title = content.select('.title')[0].text    #titlew为书籍名称对应的class

    ...:         author = content.select('.author-item')[0].text

    ...:         price = content.select('.price-tag')[0].text

    ...:         category = content.select('.category')[0].text[3:]

    ...:         rating = content.select('.rating-average')[0].text

    ...:         eveluate_nums = content.select('.ratings-link')[0].text[:-3]

    ...:         desc = content.select('.article-desc-brief')[0].text

    ...:        

    ...:         print(title,author,price,category,rating,eveluate_nums,desc)

Clipboard Image.png

是不是很兴奋!一下子就把这一个页面的内容全部抓取下来了,接下来是不是该处理第二页的内容啦,方法还是一样一样的,只要最后将所有页的内容拼接起来就OK了。你当我傻啊!这要是有个上百页上千页的,我一个星期都在搞这个,是不是效率太低了!唉~我们接下来只要发现每一页url的规律是不是就可以通过循环的方式解决这个一页一页处理的笨方法啦。我们发现原来这三个页面的url是这样的:

https://read.douban.com/search?q=Python&start=0

https://read.douban.com/search?q=Python&start=10

https://read.douban.com/search?q=Python&start=20

规律很明显,就不说啦!这里继续上代码,实现翻页般的爬虫:

生成有规律的url:

In [13]: urls = []

    ...: for i in (0,10,20):

    ...:     urls.append('https://read.douban.com/search?q=Python&start=' + str(i))

Clipboard Image.png

In [15]: for url in urls:

    ...:     #读取网页内容

    ...:     req = urllib.request.Request(url)

    ...:     res = urllib.request.urlopen(req).read().decode('utf-8')

    ...:     #解析网页

    ...:     soup = BeautifulSoup(res, 'html.parser')

    ...:     #循环的方式读取所需字段

    ...:     for content in soup.select('.info'):

    ...:         title = content.select('.title')[0].text

    ...:         if content.select('.author-item') == []:

    ...:             anthor = None

    ...:         else:

    ...:             author = content.select('.author-item')[0].text

    ...:         price = content.select('.price-tag')[0].text

    ...:         category = content.select('.category')[0].text[3:]

    ...:         if content.select('.rating-average')==[]:

    ...:             rating = None

    ...:         else:

    ...:             rating = content.select('.rating-average')[0].text

    ...:         if content.select('.ratings-link') == []:

    ...:             eveluate_nums = None

    ...:         else:

    ...:             eveluate_nums = content.select('.ratings-link')[0].text[:-3]

    ...:         if content.select('.article-desc-brief') == []:

    ...:             desc = None

    ...:         else:

    ...:             desc = content.select('.article-desc-brief')[0].text

    ...:        

    ...:         print(title,author,price,category,rating,eveluate_nums,desc)

Clipboard Image.png

 OK,到目前为止,大功已完成90%。哎?发现上图中的第二段for循环与这个不一样啊!为什么第二段循环里多出来这么对if...else的结构啊?

Clipboard Image.png

 好,这个问题问的非常有水平,这是因为有些书没有人评价,或者有人评价但没有评分。对于这样的问题,如果没有if...else就会报错,最终导致你的程序无法搜集到所需的数据,不信,你试试~

Clipboard Image.png

最后,我们得将爬取出来的数据导入到我们的数据库。前往记得,在导入数据库之前,需要在MySQL中建立好一张存数据的表:

Clipboard Image.png

 接下来使用pymysql模块将数据导入到数据库中(关于该模块的使用,可以参考利用Python读取外部数据文件),具体脚本如下(如果您操作的话,千万记得下面的代码是紧跟着print语句后面的,跟print语句齐平):

In [16]: connect = pymysql.connect(

    ...:                           host = 'localhost',

    ...:                           user = 'root',

    ...:                           password = 'snake',

    ...:                           port = 3306,

    ...:                           database = 'test',

    ...:                           charset = 'utf8')

    ...: sql = 'insert into `books`(`title`,`author`,`price`,\

    ...:                            `category`,`rating`,`eveluate_nums`,`describtion`) \

    ...:                            values (%s,%s,%s,%s,%s,%s,%s)'

    ...:

    ...: try:

    ...:     with connect.cursor() as cursor:

    ...:         cursor.execute(sql,(title,author,price,

    ...:                        category,rating,eveluate_nums,desc))

    ...:         connect.commit()

    ...:         cursor.close()

    ...: finally:

    ...:     connect.close()

效果上图:

Clipboard Image.png

 OK,如果你也按照上面的操作的话,我想你的结果应该是跟我的一样。看,这样一个简单的爬虫工作就让你实现了,是不是有点小兴奋。关于爬虫部分,还有很多需要深入学习和了解的,有兴趣的朋友可以互相交流,一起往更深的爬虫黑洞进军!

最后,再跟大家致歉,原本这期计划写《运用R语言的caret包进行特征选择》,但由于理论部分实在太难,需要一段时间消化,所以将爬虫提前推送出来。期待朋友们继续关注即将推送的《运用R语言的caret包进行特征选择》一期内容。


学习与分享,取长补短,欢迎关注博客:每天进步一点点2015

每天进步一点点2015.png

推荐 4
本文由 每天进步一点点2015 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

1 个评论

等待博主的'特征选择'的内容了。

要回复文章请先登录注册