继爬取 猫眼电影TOP100榜单 之后,再来爬一下豆瓣的书籍信息(主要是书的信息,评分及占比,评论并未爬取)。原创,转载请联系我。


需求爬取豆瓣某类型标签下的所有书籍的详细信息及评分

语言python

支持库

  • 正则、解析和搜索:re、requests、bs4、lxml (后三者需要安装)
  • 随机数:time、random

步骤三步走

  1. 访问标签页面,获取该标签下的所有书籍的链接
  2. 逐一访问书籍链接,爬取书籍信息和评分
  3. 持久化存储书籍信息(这里用了excel,可以使用数据库)

一、访问标签页面,获取该标签下的所有书籍的链接

照例,我们先看一下豆瓣的Robots.txt , 不能爬取禁止的内容。

我们这一步要爬取的标签页面,以小说为例 https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4

先去看看它的HTML结构

发现,每一本书,都在一个<li>标签当中,而我们需要的只是那张图片的链接(就是书籍页面的链接)

这样,就可以写正则或者是利用bs4(BeatuifulSoup)来获取书籍的链接。

可以看到,每一页只显示了20本书,所以需要遍历访问所有的页面,它的页面链接也是有规律的

第二页:https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4?start=20&type=T

第三页:https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4?start=40&type=T

即:start每次递增20就好了。

下面来看代码:

 # -*- coding: utf-8 -*-
# @Author : yocichen
# @Email : yocichen@126.com
# @File : labelListBooks.py
# @Software: PyCharm
# @Time : 2019/11/11 20:10 import re
import openpyxl
import requests
from requests import RequestException
from bs4 import BeautifulSoup
import lxml
import time
import random src_list = [] def get_one_page(url):
'''
Get the html of a page by requests module
:param url: page url
:return: html / None
'''
try:
head = ['Mozilla/5.0', 'Chrome/78.0.3904.97', 'Safari/537.36']
headers = {
'user-agent':head[random.randint(0, 2)]
}
response = requests.get(url, headers=headers, proxies={'http':'171.15.65.195:9999'}) # 这里的代理,可以设置也可以不加,如果失效,不加或者替换其他的即可
if response.status_code == 200:
return response.text
return None
except RequestException:
return None def get_page_src(html, selector):
'''
Get book's src from label page
:param html: book
:param selector: src selector
:return: src(list)
'''
# html = get_one_page(url)
if html is not None:
soup = BeautifulSoup(html, 'lxml')
res = soup.select(selector)
pattern = re.compile('href="(.*?)"', re.S)
src = re.findall(pattern, str(res))
return src
else:
return [] def write_excel_xlsx(items, file):
'''
Write the useful info into excel(*.xlsx file)
:param items: book's info
:param file: memory excel file
:return: the num of successful item
'''
wb = openpyxl.load_workbook(file)
ws = wb.worksheets[0]
sheet_row = ws.max_row
item_num = len(items)
# Write film's info
for i in range(0, item_num):
ws.cell(sheet_row+i+1, 1).value = items[i]
# Save the work book as *.xlsx
wb.save(file)
return item_num if __name__ == '__main__':
total = 0
for page_index in range(0, 50): # 这里为什么是50页?豆瓣看起来有很多页,其实访问到后面就没有数据了,目前是只有50页可访问。
# novel label src : https://book.douban.com/tag/%E5%B0%8F%E8%AF%B4?start=
# program label src : https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=
# computer label src : https://book.douban.com/tag/%E8%AE%A1%E7%AE%97%E6%9C%BA?start=
# masterpiece label src : https://book.douban.com/tag/%E5%90%8D%E8%91%97?start=
url = 'https://book.douban.com/tag/%E5%90%8D%E8%91%97?start='+str(page_index*20)+'&type=T' # 你要做的就是把URL前面的部分替换成你所有爬的那个标签的对应部分,确切的来说是红色加粗的文字部分。
one_loop_done = 0
# only get html page once
html = get_one_page(url)
for book_index in range(1, 21):
selector = '#subject_list > ul > li:nth-child('+str(book_index)+') > div.info > h2'
src = get_page_src(html, selector)
row = write_excel_xlsx(src, 'masterpiece_books_src.xlsx') # 要存储的文件,需要先创建好
one_loop_done += row
total += one_loop_done
print(one_loop_done, 'done')
print('Total', total, 'done')

注释比较清楚了,先获取页面HTML,正则或者bs4遍历获取每一页当中的书籍链接,存到excel文件中。

注意:如果需要直接使用我的代码,你只需要去看一下那个标签页面的链接,而后把红色加粗部分(中文标签编码)替换即可,以及先创建一个excel文件,用以存储爬到的书籍链接。


二、逐一访问书籍链接,爬取书籍信息和评分

上一步我们已经爬到了,小说标签下的所有书籍的src,这一步,就是要逐一去访问书籍的src,然后爬取书籍的具体信息。

先看看要爬的信息的HTML结构

下面是书籍信息页面结构

再是评分页面结构

这样就可以利用正则表达式和bs4库来匹配到我们所需要的数据了。(试了试纯正则,比较难写,行不通)

下面看代码

 # -*- coding: utf-8 -*-
# @Author : yocichen
# @Email : yocichen@126.com
# @File : doubanBooks.py
# @Software: PyCharm
# @Time : 2019/11/9 11:38 import re
import openpyxl
import requests
from requests import RequestException
from bs4 import BeautifulSoup
import lxml
import time
import random def get_one_page(url):
'''
Get the html of a page by requests module
:param url: page url
:return: html / None
'''
try:
head = ['Mozilla/5.0', 'Chrome/78.0.3904.97', 'Safari/537.36']
headers = {
'user-agent':head[random.randint(0, 2)]
}
response = requests.get(url, headers=headers) #, proxies={'http':'171.15.65.195:9999'}
if response.status_code == 200:
return response.text
return None
except RequestException:
return None def get_request_res(pattern_text, html):
'''
Get the book info by re module
:param pattern_text: re pattern
:param html: page's html text
:return: book's info
'''
pattern = re.compile(pattern_text, re.S)
res = re.findall(pattern, html)
if len(res) > 0:
return res[0].split('<', 1)[0][1:]
else:
return 'NULL' def get_bs_res(selector, html):
'''
Get the book info by bs4 module
:param selector: info selector
:param html: page's html text
:return: book's info
'''
soup = BeautifulSoup(html, 'lxml')
res = soup.select(selector)
# if res is not None or len(res) is not 0:
# return res[0].string
# else:
# return 'NULL'
if res is None:
return 'NULL'
elif len(res) == 0:
return 'NULL'
else:
return res[0].string # Get other info by bs module
def get_bs_img_res(selector, html):
soup = BeautifulSoup(html, 'lxml')
res = soup.select(selector)
if len(res) is not 0:
return str(res[0])
else:
return 'NULL' def parse_one_page(html):
'''
Parse the useful info of html by re module
:param html: page's html text
:return: all of book info(dict)
'''
book_info = {}
book_name = get_bs_res('div > h1 > span', html)
# print('Book-name', book_name)
book_info['Book_name'] = book_name
# info > a:nth-child(2)
author = get_bs_res('div > span:nth-child(1) > a', html)
if author is None:
author = get_bs_res('#info > a:nth-child(2)', html)
# print('Author', author)
author = author.replace(" ", "")
author = author.replace("\n", "")
book_info['Author'] = author publisher = get_request_res(u'出版社:</span>(.*?)<br/>', html)
# print('Publisher', publisher)
book_info['publisher'] = publisher publish_time = get_request_res(u'出版年:</span>(.*?)<br/>', html)
# print('Publish-time', publish_time)
book_info['publish_time'] = publish_time ISBN = get_request_res(u'ISBN:</span>(.*?)<br/>', html)
# print('ISBN', ISBN)
book_info['ISBN'] = ISBN img_label = get_bs_img_res('#mainpic > a > img', html)
pattern = re.compile('src="(.*?)"', re.S)
img = re.findall(pattern, img_label)
if len(img) is not 0:
# print('img-src', img[0])
book_info['img_src'] = img[0]
else:
# print('src not found')
book_info['img_src'] = 'NULL' book_intro = get_bs_res('#link-report > div:nth-child(1) > div > p', html)
# print('book introduction', book_intro)
book_info['book_intro'] = book_intro author_intro = get_bs_res('#content > div > div.article > div.related_info > div:nth-child(4) > div > div > p', html)
# print('author introduction', author_intro)
book_info['author_intro'] = author_intro grade = get_bs_res('div > div.rating_self.clearfix > strong', html)
if len(grade) == 1:
# print('Score no mark')
book_info['Score'] = 'NULL'
else:
# print('Score', grade[1:])
book_info['Score'] = grade[1:] comment_num = get_bs_res('#interest_sectl > div > div.rating_self.clearfix > div > div.rating_sum > span > a > span', html)
# print('commments', comment_num)
book_info['commments'] = comment_num five_stars = get_bs_res('#interest_sectl > div > span:nth-child(5)', html)
# print('5-stars', five_stars)
book_info['5_stars'] = five_stars four_stars = get_bs_res('#interest_sectl > div > span:nth-child(9)', html)
# print('4-stars', four_stars)
book_info['4_stars'] = four_stars three_stars = get_bs_res('#interest_sectl > div > span:nth-child(13)', html)
# print('3-stars', three_stars)
book_info['3_stars'] = three_stars two_stars = get_bs_res('#interest_sectl > div > span:nth-child(17)', html)
# print('2-stars', two_stars)
book_info['2_stars'] = two_stars one_stars = get_bs_res('#interest_sectl > div > span:nth-child(21)', html)
# print('1-stars', one_stars)
book_info['1_stars'] = one_stars return book_info def write_bookinfo_excel(book_info, file):
'''
Write book info into excel file
:param book_info: a dict
:param file: memory excel file
:return: the num of successful item
'''
wb = openpyxl.load_workbook(file)
ws = wb.worksheets[0]
sheet_row = ws.max_row
sheet_col = ws.max_column
i = sheet_row
j = 1
for key in book_info:
ws.cell(i+1, j).value = book_info[key]
j += 1
done = ws.max_row - sheet_row
wb.save(file)
return done def read_booksrc_get_info(src_file, info_file):
'''
Read the src file and access each src, parse html and write info into file
:param src_file: src file
:param info_file: memory file
:return: the num of successful item
'''
wb = openpyxl.load_workbook(src_file)
ws = wb.worksheets[0]
row = ws.max_row
done = 0
for i in range(868, row+1):
src = ws.cell(i, 1).value
if src is None:
continue
html = get_one_page(str(src))
book_info = parse_one_page(html)
done += write_bookinfo_excel(book_info, info_file)
if done % 10 == 0:
print(done, 'done')
return done if __name__ == '__main__':
# url = 'https://book.douban.com/subject/1770782/'
# html = get_one_page(url)
# # print(html)
# book_info = parse_one_page(html)
# print(book_info)
# res = write_bookinfo_excel(book_info, 'novel_books_info.xlsx')
# print(res, 'done')
res = read_booksrc_get_info('masterpiece_books_src.xlsx', 'masterpiece_books_info.xlsx') # 读取的src文件,要写入书籍信息的存储文件
print(res, 'done')

注意:如果要直接使用的话,需要做的只是给参数而已,第一个是上一步获取的src文件,第二个是需要存储书籍信息的文件(需要事先创建一下)


三、持久化存储书籍信息(Excel)

使用excel存储书籍的src列表和书籍的具体信息,需要使用openpyxl库进行读写excel。代码在上面write_*/read_*函数中。


效果

爬到的小说类书籍的src

爬到的书籍详细信息

后记

写这个前后大概花了有两整天吧,爬虫要做的工作还是比较细致的,需要分析HTML页面还要写正则表达式。话说,使用bs4真的是很简单,只需要copy一下selector就ok了,较正则可以大大提高效率。另外,单线程爬虫是比较蠢的。还有很多不足(诸如代码不规整,不够健壮),欢迎指正。

你可能需要的 GitHub 传送门

参考资料

【1】豆瓣robots.txt https://www.douban.com/robots.txt

【2】https://blog.csdn.net/jerrygaoling/article/details/81051447

【3】https://blog.csdn.net/zhangfn2011/article/details/7821642

【4】https://www.kuaidaili.com/free

python 爬取豆瓣书籍信息的更多相关文章

  1. python爬取豆瓣视频信息代码

    目录 一:代码 二:结果如下(部分例子)   这里是爬取豆瓣视频信息,用pyquery库(jquery的python库). 一:代码 from urllib.request import quote ...

  2. python爬取豆瓣电影信息数据

    题外话+ 大家好啊,最近自己在做一个属于自己的博客网站(准备辞职回家养老了,明年再战)在家里 琐事也很多, 加上自己 一回到家就懒了(主要是家里冷啊! 广东十几度,老家几度,躲在被窝瑟瑟发抖,) 由于 ...

  3. Python爬取豆瓣指定书籍的短评

    Python爬取豆瓣指定书籍的短评 #!/usr/bin/python # coding=utf-8 import re import sys import time import random im ...

  4. 利用Python爬取豆瓣电影

    目标:使用Python爬取豆瓣电影并保存MongoDB数据库中 我们先来看一下通过浏览器的方式来筛选某些特定的电影: 我们把URL来复制出来分析分析: https://movie.douban.com ...

  5. Python爬取豆瓣电影top

    Python爬取豆瓣电影top250 下面以四种方法去解析数据,前面三种以插件库来解析,第四种以正则表达式去解析. xpath pyquery beaufifulsoup re 爬取信息:名称  评分 ...

  6. Python爬取豆瓣《复仇者联盟3》评论并生成乖萌的格鲁特

    代码地址如下:http://www.demodashi.com/demo/13257.html 1. 需求说明 本项目基于Python爬虫,爬取豆瓣电影上关于复仇者联盟3的所有影评,并保存至本地文件. ...

  7. 零基础爬虫----python爬取豆瓣电影top250的信息(转)

    今天利用xpath写了一个小爬虫,比较适合一些爬虫新手来学习.话不多说,开始今天的正题,我会利用一个案例来介绍下xpath如何对网页进行解析的,以及如何对信息进行提取的. python环境:pytho ...

  8. Python爬取豆瓣音乐存储MongoDB数据库(Python爬虫实战1)

    1.  爬虫设计的技术 1)数据获取,通过http获取网站的数据,如urllib,urllib2,requests等模块: 2)数据提取,将web站点所获取的数据进行处理,获取所需要的数据,常使用的技 ...

  9. python爬取豆瓣小组700+话题加回复啦啦啦python open file with a variable name

    需求:爬取豆瓣小组所有话题(话题title,内容,作者,发布时间),及回复(最佳回复,普通回复,回复_回复,翻页回复,0回复) 解决:1. 先爬取小组下,所有的主题链接,通过定位nextpage翻页获 ...

随机推荐

  1. 50个实用的jq代码段整理

    个人博客: http://mcchen.club   1. 如何创建嵌套的过滤器:   //允许你减少集合中的匹配元素的过滤器,   //只剩下那些与给定的选择器匹配的部分.在这种情况下,   //查 ...

  2. python编程基础之二十二

    字典:字典属于可变对象,但是不属于序列,内部是通过哈希方式存储的,内部保存的是一个个键值对key:value 字典的键是唯一的, 字典查找速度比较快 d1 = {}  #括号里面用键值对表示 d2 = ...

  3. bugku 很普通的数独

    下载下是一个没有后缀的文件,使用winhex打开,头文件为50 4b 03 为zip文件,修改后缀,打开压缩包,是一大堆数独图片. 仔细看了好久,发现这几张图片像二维码,而且1 5 21这三张图的位置 ...

  4. mac上git安装与github基本使用

    目录 安装git 创建ssh key.配置git 提交本地项目到GitHub 一.安装Git MAC安装Git 首先查看电脑是否安装Git,终端输入: git 1.通过homebrew安装Git 1. ...

  5. VM虚拟机启动夜神模拟器卡99%解决办法

    VM虚拟机启动夜神模拟器卡99%解决办法 本人出现的情况: 物理机装的是win7系统,安装了vmware14(安装过程未出现报错),在vmware14 上 win10系统(安装过程未出现报错),安装夜 ...

  6. RF自定义库和关键字

    1:在D:\work_software\python\Lib\site-packages 文件夹下, 新建python package文件夹 ,例如我的是TestLibrary 建好后的完整路径:D: ...

  7. opencv::Laplance算子

    Laplance算子 理论:在二阶导数的时候,最大变化处的值为零即边缘是零值.通过二阶导数计算,依据此理论我们可以计算图像二阶导数,提取边缘. 拉普拉斯算子(Laplance operator) 处理 ...

  8. LeetCode初级算法--排序和搜索01:第一个错误的版本

    LeetCode初级算法--排序和搜索01:第一个错误的版本 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.cs ...

  9. java面试官:兄弟简单谈谈Static、final、Static final各种用法吧

    前言 对Static.final.Static final这几个关键词熟悉又陌生?想说却又不知怎么准确说出口?好的,本篇博客文章将简短概要出他们之间的各自的使用,希望各位要是被你的面试官问到了,也能从 ...

  10. human_pose_estimation_demo的再进一步研究

    这次研究的主要是速度问题,后来还获得了其它方面的收获. 1.原始的抽帧       对于这样一个问题,想提高速度,能够想到的最简单.最直接的方法就是“抽帧”.比如添加一个计数器 这里,只有当Sumof ...