爬虫练习-百度新闻

爬虫练习-豆瓣读书

昨晚使用不熟悉的xpath语法解析百度新闻页面碰到了好多坑,今天继续通过简单的豆瓣图书进行练习

1.分析页面

进入豆瓣首页https://www.douban.com/在第一行导航栏找到读书:https://book.douban.com/

进入页面之后发现有很多内容,由于豆瓣没有反爬措施,所以多抓取些数据

大致浏览后发现应该能通过标签查找到全部图书,找到所有热门标签点击所有热门标签https://book.douban.com/tag/?view=cloud

浏览页面后大致可以确定这个入口是合适的一个入口

2.分析入口页面

打开浏览器自带的开发者模式找到其中一个标签:小说

1
<td><a href="/tag/小说">小说</a>

点击小说:https://book.douban.com/tag/小说发现它的url就是域名https://book.douban.com//tag/小说的组合

3.分析tag页面

进入小说页面之后发现一本书大概分为8个关键部分:封面,书名,作者,出版社,日期,售价,评分,简介

1
2
3
4
5
6
7
8
9
10
11
<img class="" src="https://img3.doubanio.com/mpic/s27264181.jpg" width="90">

<ahref="https://book.douban.com/subject/25862578/" title="解忧杂货店"onclick="...">解忧杂货店</a>

<div class="pub">[日] 东野圭吾 / 李盈春 / 南海出版公司 / 2014-5 / 39.50元</div>

<span class="rating_nums">8.6</span>

<p>现代人内心流失的东西,这家杂货店能帮你找回——
僻静的街道旁有一家杂货店,只要写下烦恼投进卷帘门的投信口,第二天就会在店后的牛奶箱里得到回答。
因男友身患绝... </p>

4.开始

首先导入需要的库

1
2
from lxml import etree
import requests

这次使用类的方式实现

1
2
class DouBanBook():
pass

初始化:

1
2
3
def __init__(self):
self.url_book = 'https://book.douban.com/tag/?view=cloud'
self.page = 0

获取tag列表

1
2
3
4
5
6
7
8
9
10
11
12
def get_tags(self):
'''
获取tag列表
'''
tags = [] #创建一个空列表存储tag名
result = requests.get(self.url_book).text
#开始xpath解析
html = etree.HTML(result)
tags_list = html.xpath('//[@id="content"]/div/div[1]/div[2]/div/table/tbody/tr/td/a')
for tag in tags_list:
tags.append(''.join(tag.xpath('./text()')))
return tags

存储入mysql数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
def insert_mysql(self,item):
#连接数据库
db = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123456', db='douban',charset="utf8")
#写sql语句
sql = "INSERT INTO douban_book(tag,pic,titiel,author,press,price,time,score,book_info) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s);"
#尝试插入数据
try:
with db.cursor() as cursor:#创建游标
cursor.execute(sql, (item['tag'],item['book_pic'],item['book_titiel'],item['book_author'],item['book_press'],item['book_price'],item['book_time'],item['book_score'],item['book_info']))
db.commit()#提交数据
except Exception as e:
cursor.execute(sql,('1','1',item['book_titiel'],'1','1','1','1','1','1',))
db.commit()

将八项重要内容写入数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def get_book_message(self,tag):
'''
将八项重要信息存储到mysql数据库
'''
#拼接tag和page成新的url
url = 'https://book.douban.com/tag/'+tag+'?start=%d&type=T' %self.page
result = requests.get(url).text
#开始xpath解析
html = etree.HTML(result)
books_list = html.xpath('//*[@id="subject_list"]/ul/li')
#由于翻页操作是通过回调函数实现,所以需要做跳出循环的判断
if books_list == []:
return
item = {}#新建一个空字典存储获取到的信息
item['tag'] = tag
for book in books_list:
#封面
item['book_pic'] = ''.join(book.xpath('./div[1]/a/img/@src'))
#书名
item['book_titiel'] = ''.join(book.xpath('./div[2]/h2/a/@title'))

_book_press = book.xpath('./div[2]/div[1]/text()')[0].split('\n')
#由于作者,出版社,时间,售价是通过/分割的所以写一个列表推倒式存储
book_press = ''.join([book_press for book_press in _book_press if '/' in book_press])
#作者/出版社/时间/售价
#查看多条数据后发现最后一条必为价格,最后第二条为时间,最后第三条为出版社
item['book_price'] = book_press.split('/')[-1]
item['book_time'] = book_press.split('/')[-2]
item['book_press'] = book_press.split('/')[-3]
item['book_author'] = ''.join(book_press.split('/')[:-3])
#评分
item['book_score'] = ''.join(book.xpath('./div[2]/div[2]/span[2]/text()'))
#简介
item['book_info'] = ''.join(''.join(book.xpath('./div[2]/p/text()')).split('\n'))
self.insert_mysql(item)#写入数据库
#print(item)
self.page += 20
self.get_book_message(tag)

整个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class DouBanBook():
def __init__(self):
self.url_book = 'https://book.douban.com/tag/?view=cloud'
self.page = 0
def get_tags(self):
'''
获取tag列表
'''
tags = [] #创建一个空列表存储tag名
result = requests.get(self.url_book).text
#开始xpath解析
html = etree.HTML(result)
tags_list = html.xpath('//[@id="content"]/div/div[1]/div[2]/div/table/tbody/tr/td/a')
for tag in tags_list:
tags.append(''.join(tag.xpath('./text()')))
return tags

def get_book_message(self,tag):
'''
将八项重要信息存储到mysql数据库
'''
#拼接tag和page成新的url
url = 'https://book.douban.com/tag/'+tag+'?start=%d&type=T' %self.page
result = requests.get(url).text
#开始xpath解析
html = etree.HTML(result)
books_list = html.xpath('//*[@id="subject_list"]/ul/li')
#由于翻页操作是通过回调函数实现,所以需要做跳出循环的判断
if books_list == []:
return
item = {}#新建一个空字典存储获取到的信息
item['tag'] = tag
for book in books_list:
#封面
item['book_pic'] = ''.join(book.xpath('./div[1]/a/img/@src'))
#书名
item['book_titiel'] = ''.join(book.xpath('./div[2]/h2/a/@title'))

_book_press = book.xpath('./div[2]/div[1]/text()')[0].split('\n')
#由于作者,出版社,时间,售价是通过/分割的所以写一个列表推倒式存储
book_press = ''.join([book_press for book_press in _book_press if '/' in book_press])
#作者/出版社/时间/售价
#查看多条数据后发现最后一条必为价格,最后第二条为时间,最后第三条为出版社
item['book_price'] = book_press.split('/')[-1]
item['book_time'] = book_press.split('/')[-2]
item['book_press'] = book_press.split('/')[-3]
item['book_author'] = ''.join(book_press.split('/')[:-3])
#评分
item['book_score'] = ''.join(book.xpath('./div[2]/div[2]/span[2]/text()'))
#简介
item['book_info'] = ''.join(''.join(book.xpath('./div[2]/p/text()')).split('\n'))
self.insert_mysql(item)#写入数据库
#print(item)
self.page += 20
self.get_book_message(tag)

def insert_mysql(self,item):
db = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123456', db='douban',charset="utf8")
sql = "INSERT INTO douban_book(tag,pic,titiel,author,press,price,time,score,book_info) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s);"

try:
with db.cursor() as cursor:
cursor.execute(sql, (item['tag'],item['book_pic'],item['book_titiel'],item['book_author'],item['book_press'],item['book_price'],item['book_time'],item['book_score'],item['book_info']))
db.commit()
except Exception as e:
cursor.execute(sql,('1','1',item['book_titiel'],'1','1','1','1','1','1',))
db.commit()

开始调用:

由于全部图书有点多,使用线程池加快点速度并记录下耗时

1
2
3
4
5
6
7
8
9
10
11
if __name__ == '__main__':
starttime = time.time()
book = DouBanBook()
p = Pool()
for tag in book.get_tags():
p.apply_async(book.get_book_message,args=(tag,))

p.close()
p.join()
usetime = time.time()-starttime
print('总耗时%s'%usetime)
1
2
3
4
5
from multiprocessing import Pool #进程池
from lxml import etree #lxml解析页面
import pymysql #连接mysql数据库了
import requests #模拟http/https访问
import time #时间模块
 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
您的支持将鼓励我继续创作!