准备搞事情之豆瓣爬虫篇
接到一个任务要做一个关于豆瓣的爬虫,那首先我们需要确定目标是谁,那就是下面这个网址:
https://book.douban.com/top250
很完美的一个网址,主网址后面加上站名,emmmm……似乎可以渗透测试一些……
醒醒!醒醒!
那么回到正确的路线上来~
第一步
当然是确定需求了,谁也不希望经历被产品经理在中间改需求的悲惨遭遇。
因为很喜欢这种黑色的背景,所以需求也写在这里了
需求:
使用Python语言制作如下功能
创建个数据库
使用网络爬虫爬取豆瓣250大图书排行榜
爬回前100名的图书的信息,并记录在数据库中需要记录每本书的书名、作者、出版社、封面图像连接、短评
每笔数据限用一笔数据多个栏位,每笔数据的ID要设定为Primary Key ,值使用每本书的豆瓣链接位置
第二步
当然是分析网页了,不要问,不要说,一切尽在不言中~
F12直接打开网页代码
我就直接贴出来了,吼吼吼吼
<p class="ulfirst"></p>
<table width="100%">
<tr class="item">
<td width="100" valign="top">
<a class="nbg" href="https://book.douban.com/subject/1007305/"
onclick="moreurl(this,{i:'0'})"
>
<img src="https://img1.doubanio.com/view/subject/s/public/s1070959.jpg" width="90" />
</a>
</td>
<td valign="top">
<div class="pl2">
<a href="https://book.douban.com/subject/1007305/" onclick="moreurl(this,{i:'0'})" title="红楼梦"
>
红楼梦
</a>
</div>
<p class="pl">[清] 曹雪芹 著 / 人民文学出版社 / 1996-12 / 59.70元</p>
<div class="star clearfix">
<span class="allstar50"></span>
<span class="rating_nums">9.6</span>
<span class="pl">(
258506人评价
)</span>
</div>
<p class="quote" style="margin: 10px 0; color: #666">
<span class="inq">都云作者痴,谁解其中味?</span>
</p>
</td>
</tr>
</table>
<p class="ul"></p>
好的,现在这就是一段完整的一本书的标签,我们根据需求知道,我们需要的值分别是:书名、作者、出版社、封面图像连接、短评
第三步
第三步当时就是敲代码了,工欲善其事必先利其器,我们先要挑一件趁手的兵器才行。
经过层层筛选,我终于决定用如下几个库作为我的神兵利器
import pymysql
from lxml import etree
import requests
第一个:pymysql,MySQL数据库调用神器
第二个:网页分析神器,可以过滤出你想要的所有标签
第三个:神级工具,引用网上的说法就是Requests是一个基于Apache2协议开源的Python HTTP库,号称是“为人类准备的HTTP库”。
第四步
其实就是一大段苦不堪言的debug环节,各种奇葩的bug,但是就像我开头说的那样,这是一篇拖了很久很久的文章,有许多有趣的问题都忘记了,只记得几个印象深刻的,下面开始:
1)关于Xpath的语法
message = selector.xpath('//tr[@class="item"]')
我们发现我们一本书的所有的目标元素都在一个很大的tr标签下,所以咱们只需把这个标签当作母体,分析每一个此标签下的元素情况,并将这些元素挑选出来即可。
bookname = mes.xpath('td/div/a/@title')
解释:这个语法其实很好理解,首先这个例子是要得到书名,那么咱们查看源码的时候可以知道书名是在一个a 标签里面并且它包含于一个叫title的属性名里面,同时这个a标签又在一个td标签和一个div下,因此咱们直接定位到这里就可以。
bookurl = mes.xpath('td/div/a/@href')
bookname = mes.xpath('td/div/a/@title')
bookinfos = mes.xpath('td/p/text()')[0]
bookauthor = bookinfos.split('/')[0]
bookpublisher = bookinfos.split('/')[-3]
bookcomments = mes.xpath('td/p/span/text()')
那么有了上面的分析,我很快就得到所有目标的xpath路径,但是这里有个值得咱们注意的是bookcomments标签,因为这个标签可能为空,所以咱们需要处理一下它,判断是否为空,要是真为空咱们也没办法是吧,为空咱们就给个赋值=“空”就可以了,那么我是这样写的:
comment = bookcomments if len(bookcomments) != 0 else "nope"
2)关于处理列表数据
其实这个列表数据的处理就是你的python语法基础打得牢不牢固就在这里体现出来了,那么很显然我的语法知识并不牢固,所以我在做数据处理的总是会出现不知道咱们处理这一段数据的情况,那么经过刚才的处理咱们已经得到了我们需要的信息,接下来就是将它们放入一个列表里(当然你说要放进字典里或者其它我也表示没问题)
try:
# 将获取到的信息放进列表中
self.doubandata.append((bookurl, bookname, bookauthor, bookpublisher, comment))
except:
return print('[INFO: FAIL TO ADD]')
就是上面这简单的一步,让我在当时结结实实的喝了一壶。
为什么呢,因为咱们是不是需要把每本书的书名、作者、出版社、封面图像连接、短评存入数据库中,并且每笔数据限用一笔数据多个栏位,那么一本书就是一行,每一列分别是一个目标元素对吧,当时我就这样搞:
douban_list = []
self.doubandata.append(bookurl, bookname, bookauthor, bookpublisher, comment)
结果总是报错,后来仔细一想才再加多一个括号,因为咱们要把它作为同一栏的数据,这个玩意现在说起来我都觉得太简单不过,当时当局者迷啊~
3)关于数据库操作
当时这个数据库语言也是把我整的够呛,首先我的数据版本号是
8.0.18 MySQL Community Server - GPL
怎么查数据库版本号:MySQL -V(注意大小写)
有一个很坑的是建库语句中,单引号用的是键盘tab键上面的—> ` <-----
没错,它不是双引号下面的那个单引号!
啊啊啊啊啊啊啊!当年我快被逼疯了好吗!
还有一个印象比较深的是插入语句中,有一个execute和executemany,这里咱们需要明白的是:execute是循环插入数据,一次就插入一条。但是我那么庞大的数据量怎么搞快一点呢那就是批量插入数据executemany函数了,下面是使用的栗子:
noun.executemany(self.sql_insert, self.doubandata)
最后的最后
啊~这篇迟到的博客终于写到了尾声,由于技术不嘉,所以有不对或者值得改进的地方欢迎各位大佬联系我或留言,最后跪献上我的源代码:
# author:Cooper.David.H
import pymysql
from lxml import etree
import requests
# 建立类doubandushu
class doubandushu:
# 定义默认参数
def __init__(self):
# 请求头
self.url_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/79.0.3945.88 Safari/537.36'}
# 爬取目标网址
self.doubanurl = 'https://book.douban.com/top250?start={}'
# 存储爬取到的数据的列表
self.doubandata = []
# SQL语句,将数据存入数据库
self.sql_insert = "INSERT INTO douban(url,name,author,publisher,comment) VALUES (%s,%s,%s,%s,%s)"
# 连接数据库函数
def doubanbooks(self):
doubandb = pymysql.connect('localhost', 'root', '123456', 'douban_db')
noun = doubandb.cursor()
noun.executemany(self.sql_insert, self.doubandata)
doubandb.commit()
print('[INFO:SUCCESSS TO FINISHED]')
# 爬虫函数
def get_book(self):
# 爬前四页:一页25条数据,因此刚好100条数据
urls = [self.doubanurl.format(i) for i in range(0, 4, 1)]
for url in urls:
html = requests.get(url, headers=self.url_header)
selector = etree.HTML(html.text)
message = selector.xpath('//tr[@class="item"]')
# 用xpath解析网页,获取书名,链接等信息
for mes in message:
bookurl = mes.xpath('td/div/a/@href')
bookname = mes.xpath('td/div/a/@title')
bookinfos = mes.xpath('td/p/text()')[0]
bookauthor = bookinfos.split('/')[0]
bookpublisher = bookinfos.split('/')[-3]
bookcomments = mes.xpath('td/p/span/text()')
comment = bookcomments if len(bookcomments) != 0 else "nope"
print(bookurl, bookname, bookauthor, bookpublisher, comment)
try:
# 将获取到的信息放进列表中
self.doubandata.append((bookurl, bookname, bookauthor, bookpublisher, comment))
except:
return print('[INFO: FAIL TO ADD]')
if __name__ == '__main__':
# 实例化对象
douban = doubandushu()
try:
# 执行函数
douban.get_book()
douban.doubanbooks()
except:
print('fail')
原文链接:https://blog.csdn.net/Huanghua_D/article/details/104664161