requests 获取div_爬虫系列第五篇 使用requests与BeautifulSoup爬取豆瓣图书Top250

上一篇我们学习了BeautifulSoup的基本用法,本节我们使用它来爬取豆瓣图书Top250。

一、网页分析

我们爬取的网页的url是https://book.douban.com/top250?icn=index-book250-all。首页如图

01bded5e39063b35674a49cf2f0593f8.png

与豆瓣电影Top250差不多,将页面拉到最底部,可以看到分页列表

5926e492a73c567f8b6d695dea2e462e.png

并且每一页的url也是以25递增,所以爬取思路与豆瓣电影Top250一致。

二、爬取目标

我们本篇要爬取的信息包括书名、作者、出版社、价格、评分、推荐语。

三、爬取首页

  • 网页获取源代码
import requestsdef get_html(url):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}html = requests.get(url,headers=headers)return html.textif __name__ == '__main__':url = 'https://book.douban.com/top250?start=0'html = get_html(url)print(html)

输出结果

44b55bdfc4df8275bc398f8a901d7c68.png
  • 解析提取所需信息

ab1e9bae3bc1b77647f462869dbd330e.png

如图,查看源代码我们可以知道页面中书的信息均包含在一个个<table>标签中,所以我们可以先用CSS选择器将一个个<table>节点选出来,然后在使用循环提取每一本书的信息。提取<table>节点的代码如下:

def parse_html(html):soup = BeautifulSoup(html,'lxml')books = soup.select('div.article div.indent table')print(books)

运行结果如下:

5c4c171a10ceb403fab49be7234c6673.png

可以看到输出为列表,并且第一个元素包含《追风筝的人》的相关信息。这里我们使用BeautifulSoup中的select()加CSS选择器提取<table>节点。传入的CSS选择器为:div.article div.indent table。其中div.article的意思为选择包含属性class="article"的<div>标签,然后跟空格代表嵌套关系,表示接着选择该<div>下的包含class="indent"的<div>标签,再跟空格表示接着嵌套,继续选择第二个<div>标签下的<table>标签。

接下来,对选出来的<table>标签循环,在每一个<table>标签中去提取图书信息。这里我们先提出书名信息,先看一种写法,代码如下:

def parse_html(html):soup = BeautifulSoup(html,'lxml')books = soup.select('div.article div.indent table')for book in books:title = book.div.a.stringprint(title)

输出结果

b1519dccb87379971550020f39be6d78.png

可以看到确实获取到了书名信息,但是有些书的书名没有得到,返回了None,这就不是很完美了呀。我们先解释写这里获取标题的方法,这里我们使用了节点选择器的嵌套选择:首先选择了<div>标签,然后继续选择其下的<a>标签。为什么不直接选择<a>标签呢,因为包含书名信息的<a>标签是<table>节点下的第二个<a>标签,直接选择<a>只会选择第一个不包含书名信息的那个<a>标签。下面我们来研究下为什么使用string属性不能获取某些书的书名信息,我们先将获取到的<a>标签打印出来。

def parse_html(html):soup = BeautifulSoup(html,'lxml')books = soup.select('div.article div.indent table')for book in books:title = book.div.aprint(title)

并截取返回None的那本书的位置

9b6a034def093f40caea75f30757a38a.png

可以看到《三体》这本书的<a>标签的内部结构不同,所以导致调用string属性返回None,但是我们可以注意到每条<a>标签都包含title属性,我们是否可以通过title属性获取书名?

def parse_html(html):soup = BeautifulSoup(html,'lxml')books = soup.select('div.article div.indent table')for book in books:title = book.div.a['title']print(title)

输出结果如下:

9f4fbdcdaa4ace9c88713b32fe68c1b2.png

可以看到不仅获取到了想要的信息,而数据更加干净。这里获取title部分说了这么多主要是想告诉大家一个获取相同的信息有很多的方法,当一种获取方式不理想时可以考虑换一种思路。

接下来我们一次性将所有的信息抓取下来。

def parse_html(html):soup = BeautifulSoup(html,'lxml')tables = soup.select('div.article div.indent table')books = []for table in tables:title = table.div.a['title']'''由于information中包含多个信息,某些书与大多数书的信息格式不一致在进行列表索引的时候非常容易引起IndexError异常,为了保证爬虫的健壮性我们对该异常进行处理'''information = table.p.stringinformations = information.split('/')while(len(informations)>4):del informations[1]try:author = informations[0]press = informations[1]date = informations[2]price = informations[3]except IndexError:continue'''像这样子进行数据提取很容易遇到某一个特殊部分的网页结构与大部分的不一样,这会导致首页能抓取到的节点,在该部分会返回None,从而导致调用string属性产生AttributeError异常,我们需要进行异常处理'''try:score = table.find(attrs={'class':'rating_nums'}).stringrecommendation = table.find(attrs={'class':'inq'}).stringexcept AttributeError:continuebook = {'书名':title,'作者':author,'出版社':press,'出版日期':date,'价格':price,'评分':score,'推荐语':recommendation}books.append(book)return books

输出结果:

86d94e61ad6163d11caeee3f49a8cc16.png

这里可以看到输出结果虽然为字典,但是不好看。保存为字典格式只是方便存储与后续使用,假如我们要将其打印到屏幕上的话,并不好看,所以我们接着写一个打印函数,专门用于输出:

def print_(books):for book in books:print('*'*50)for key,value in zip(book.keys(),book.values()):print(key+':'+value)print('*'*50)

我们将爬取首页的代码汇总在一起,看看输出效果

import requests
from bs4 import BeautifulSoupdef get_html(url):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}html = requests.get(url,headers=headers)return html.textdef parse_html(html):soup = BeautifulSoup(html,'lxml')tables = soup.select('div.article div.indent table')books = []for table in tables:title = table.div.a['title']'''由于information中包含多个信息,某些书与大多数书的信息格式不一致在进行列表索引的时候非常容易引起IndexError异常,为了保证爬虫的健壮性我们对该异常进行处理'''information = table.p.stringinformations = information.split('/')while(len(informations)>4):del informations[1]try:author = informations[0]press = informations[1]date = informations[2]price = informations[3]except IndexError:continue'''像这样子进行数据提取很容易遇到某一个特殊部分的网页结构与大部分的不一样,这会导致首页能抓取到的节点,在该部分会返回None,从而导致调用string属性产生AttributeError异常,我们需要进行异常处理'''try:score = table.find(attrs={'class':'rating_nums'}).stringrecommendation = table.find(attrs={'class':'inq'}).stringexcept AttributeError:continuebook = {'书名':title,'作者':author,'出版社':press,'出版日期':date,'价格':price,'评分':score,'推荐语':recommendation}books.append(book)return booksdef print_(books):for book in books:print('*'*50)for key,value in zip(book.keys(),book.values()):print(key+':'+value)print('*'*50)if __name__ == '__main__':url = 'https://book.douban.com/top250?start=0'html = get_html(url)books = parse_html(html)print_(books)

输出结果:

c3107d034a7a13b73b092eb6592da256.png

注意,这里我们没有写存储的相关函数,因为这里只为演示BeautifulSoup的用法,假如需要存储数据参考爬虫系列第三篇 使用requests与正则表达式爬取豆瓣电影Top250

四、爬取整个豆瓣图书Top250

与前面个爬虫实例一样,构造url列表,使用循环即可。全部代码如下

import requests
from bs4 import BeautifulSoupdef get_html(url):headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}html = requests.get(url,headers=headers)return html.textdef parse_html(html):soup = BeautifulSoup(html,'lxml')tables = soup.select('div.article div.indent table')books = []for table in tables:title = table.div.a['title']'''由于information中包含多个信息,某些书与大多数书的信息格式不一致在进行列表索引的时候非常容易引起IndexError异常,为了保证爬虫的健壮性我们对该异常进行处理'''information = table.p.stringinformations = information.split('/')while(len(informations)>4):del informations[1]try:author = informations[0]press = informations[1]date = informations[2]price = informations[3]except IndexError:continue'''像这样子进行数据提取很容易遇到某一个特殊部分的网页结构与大部分的不一样,这会导致首页能抓取到的节点,在该部分会返回None,从而导致调用string属性产生AttributeError异常,我们需要进行异常处理'''try:score = table.find(attrs={'class':'rating_nums'}).stringrecommendation = table.find(attrs={'class':'inq'}).stringexcept AttributeError:continuebook = {'书名':title,'作者':author,'出版社':press,'出版日期':date,'价格':price,'评分':score,'推荐语':recommendation}books.append(book)return booksdef print_(books):for book in books:print('*'*50)for key,value in zip(book.keys(),book.values()):print(key+':'+value)print('*'*50)if __name__ == '__main__':urls = [f'https://book.douban.com/top250?start={i*25}' for i in range(0,10)]for url in urls:  html = get_html(url)books = parse_html(html)print_(books)

五、总结

通过本篇的学习,读者应该着重掌握:

  • BeautifulSoup库三种节点选择方式的灵活运用
  • 对可能的异常要进行处理(请求部分的异常一般不用处理)
  • 与正则表达式进行优劣比较
  • 读者可以自行将正则表达式与BeautifulSoup结合起来灵活使用

这里解释一下为什么请求部分的异常一般不需要处理,因为请求出现异常一般意味着url错误、网络连接有问题等,这些异常都需要我们处理好而不是用try...except语句跳过它,否则爬虫无法继续。

如果觉得本篇文章不错,欢迎关注我的爬虫系列教程公众号【痕风雨】,一起学习交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468707.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python--socket套接字/TCP

socket套接字/TCP 一 客户端/服务器架构 C/S架构&#xff0c;包括 硬件C/S架构&#xff08;打印机&#xff09;软件C/S 架构&#xff08;web服务&#xff09;C/S架构的软件&#xff08;软件属于应用层&#xff09;是基于网络进行通信的Server端要&#xff1a; 1.力求一直提供服…

uniapp封装网络请求_八张图带你走进“通过一个完美请求封装一个网络模块”

本文提供视频课程讲解&#xff0c;需要的小伙伴可以点赞私信‘’网络模块‘’前往领取学习大纲1、网络模块在应用中的地位1.1当今占统治地位的网络组件OKHttp OkHttp 是一个相对成熟的解决方案&#xff0c;据说 Android4.4 的源码中可以看到 HttpURLConnection 已经替换成 OkHt…

毕业的这0111年

1.2004年&#xff0c;不知道大家对这个时间有没有感觉&#xff0c;那几年我正在读高中&#xff0c;韩寒的《三重门》席卷校园&#xff0c;同样还有郭敬明的《夏至未至》。那时候的我&#xff0c;还挣扎在温饱阶段&#xff0c;我每天吃饭的时候都想上食堂的三楼吃风味&#xff0…

我的互助小蜜圈

写在前面 从不久之前到现在&#xff0c;我的微信公众号从一个小小小阶段到了另一个小小阶段&#xff0c;非常感谢各位读者对我的信任和支持&#xff0c;当然我也是非常用心的维护这这群大佬&#xff0c;时刻想着怎样给各位大佬做好服务 &#xff0c;比如我正在溜娃&#xff0c…

比较两个表格的不同_两表数据的核对,WPS表格似乎更加方便容易

在EXCEL中的两个表格的数据对比&#xff0c;可能使用的方法会采用到查询语句&#xff0c;VBA之类的。显得在使用的过程显得有些复杂。在不经间发现WPS表格的功能处理此类的问题显得就比较的简单的多。查看并标识出分数相同的内容如下面的分数表&#xff0c;选择分数栏的范围&am…

我的知识小密圈

写在前面从不久之前到现在&#xff0c;我的微信公众号从一个小小小阶段到了另一个小小阶段&#xff0c;非常感谢各位读者对我的信任和支持&#xff0c;当然我也是非常用心的维护这这群朋友&#xff0c;时刻想着怎样给大家做好服务 &#xff0c;比如我正在溜娃&#xff0c;隔断时…

vk_down 每次下翻丙行 c++_笔记本接口不够用?不妨试试这款Type-C拓展坞,给你7个接口用...

随着笔记本电脑越来越轻薄化&#xff0c;已经很难再布局较多的数据接口了&#xff0c;但是在办公等环境下总是需要这些接口来满足需求。就拿小新个人来说&#xff0c;使用的是小米笔记本12.5寸款的&#xff0c;该款笔记本仅有三个接口&#xff0c;分别是全功能 USB-C 接口 x 1、…

学习,才是最好的投资~

推荐语&#xff1a;我因为王小波常说而喜欢的英国哲学家罗素的一句话&#xff1a; 参差多态乃是幸福的本源。正是因为有了多种多样的行业&#xff0c;才使得我们的职业也是多种多样&#xff0c;行行出大牛&#xff01;这个世界天生就注定有人搞互联网的&#xff0c;Linux&#…

第二百四十八节,Bootstrap轮播插件

Bootstrap轮播插件 学习要点&#xff1a; 1.轮播插件 本节课我们主要学习一下 Bootstrap 中的轮播插件。 一&#xff0e;轮播 轮播插件就是将几张同等大小的大图&#xff0c;按照顺序依次播放。 基本实例。 第一步&#xff0c;给轮播器区域div设置一个id给轮播器区域div设置样…

xgboost分类_XGBoost(Extreme Gradient Boosting)

一、XGBoost在Ensemble Learning中的位置机器学习中&#xff0c;有一类算法叫集成学习&#xff08;Ensemble Learning&#xff09;&#xff0c;所谓集成学习&#xff0c;指将多个分类器的预测结果集成起来&#xff0c;作为最终预测结果&#xff0c;它要求每个分类器具备一定的“…

Android技术架构演进与未来

本文阅读大约需15分钟 引言众所周知&#xff0c;Android是谷歌开发的一款基于Linux的开源操作系统&#xff0c;每年迭代一次大版本升级。 小米、华为、OPPO、VIVO、三星等各大厂商对Android原生系统进行二次开发衍生出具有各家特色的系统&#xff08;比如MIUI&#xff09;&…

Hibernate_1_配置文件详解_基础案例_Hibernate工具类_API详解_持久化类编写规则

Hibernate( ORM框架 ) Hibernate是一个数据持久化层的ORM框架. 它通过JavaBean, 数据库中的表与自身的映射关系达到表中数据的增删改查 特性 1.对JDBC访问数据库的代码进行封装, 简化数据访问的重复性代码 2.使用反射机制完成对Bean的封装 3.轻量级框架,支持关系型数据库 核…

建筑电气工程设计常用图形和文字符号_建筑水电图纸看不懂?10年老师傅教你看图技巧,分分钟安排...

1、建筑给排水工程包括&#xff1a;给水、排水、热水、消火栓、自动喷淋等常用系统&#xff0c;其管道当中流动的是水。(其管道输送介质为水)2、给排水系统的主要功能&#xff1a;(1)建筑给水系统的任务&#xff0c;就是经济合理地将水由室外给水管网输送到装置在室内的各种配水…

Android系统架构开篇

Android系统庞大且错综复杂&#xff0c;Gityuan带领大家初探Android系统整体架构&#xff0c;一窥其全貌。一、引言本文作为Android系统架构的开篇&#xff0c;起到提纲挈领的作用&#xff0c;从系统整体架构角度概要讲解Android系统的核心技术点&#xff0c;带领大家初探Andro…

20155220 实验三 敏捷开发与XP实践 实验报告

20155220 实验三 敏捷开发与XP实践 实验报告 实验内容 XP基础XP核心实践相关工具实验要求 没有Linux基础的同学建议先学习《Linux基础入门&#xff08;新版&#xff09;》《Vim编辑器》 课程完成实验、撰写实验报告&#xff0c;实验报告以博客方式发表在博客园&#xff0c;注意…

Android binder 框架和学习资料

&#xff11;Android binder 是学习 Android 系统一定要啃得硬骨头&#xff0c;可能你刚开始的时候并不理解其中的精髓&#xff0c;但是在 android 系统的很多地方你都会遇到它。不过要我自己写明白其中的逻辑脉络需要花费太多的时间和精力&#xff0c;而且传播效果也不是非常好…

Spring_Bean配置_生命周期_注解

Spring Spring是一个开源框架&#xff0c;Spring是于2003 年兴起的一个轻量级的Java 开发框架&#xff0c;由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之…

完全理解Gson(1):简单入门

GSON是Google开发的Java API&#xff0c;用于转换Java对象和Json对象。本文讨论并提供了使用API的简单代码示例。更多关于GSON的API可以访问&#xff1a;http://sites.google.com/site/gson/. 本文是GSON系列文章的第一篇。本文是其他文章的基础&#xff0c;因此不需要任何GSON…

创业碎碎念

&#xff11;今天&#xff0c;跟几条跟我玩的比较好的篮球狗在讨论人生&#xff0c;其中有一条特别感慨&#xff0c;「为何看上去别人做起来这么容易的事&#xff0c;我们做很难&#xff1f;」。我突然不知道如何去回答这样的问题&#xff1f;这个问题也一直困扰着我。读我文章…

压缩过的js代码怎么还原_Fundebug 前端 JS插件更新至 1.7.0,拆分录屏代码,还原部分 Script error....

摘要&#xff1a; BUG 监控插件压缩至 18K。1.7.0拆分了录屏代码&#xff0c;BUG 监控插件压缩至18K&#xff0c;另外我们还原了部分 Script error&#xff0c;帮助用户更方便地 Debug。请大家及时更新哈~拆分录屏代码从1.7.0版本开始&#xff0c;我们拆分了录屏代码。如果需要…