系列文章目录
我们上一讲已经学习了request的用法。
现在我们需要来处理得到的HTML信息。
本章节我们使用BeautifulSoup。漂亮的汤
耗时约15min,建议实操。
使用的网站延续前一讲。
这一小节我们的任务是得到网站上的基础信息,比如作者等。
文章目录
前言
HTML的本质还是文本。那么对于python而言就是字符串。
所以从网页中提取信息,就变成了从字符串中提取子字符串。
但是又有什么不同呢?
-
HTML的文本并不是线性的,而是树形的(DOM树)。
-
HTML有很多标签属性等,这些和目标信息强相关。
所以提取子字符串有其特定的方法
一、BeautifulSoup是什么?
beautifulsoup4库,也称为Beautiful Soup库或者bs4库,用于解析和处理HTML和XML。
名字有那么点恶趣味,但是功能还是很强大的。
pip install beautifulsoup4
import bs4
print bs4
# 最经常
from bs4 import BeautifulSoup
二、使用步骤
1.使用HTML数据构建soup
代码如下(示例):
soup = BeautifulSoup(html_text, 'html.parser')
print(soup.p.string) # 第一段的字符串内容
# 作 者:圣骑士的传说
这里用.去索引信息,是比较简单的情形,所以有缩写。。。
但是真正主力的是接下来的两个工具。
2.soup.find(‘tagName’)
:param name: A filter on tag name. 一般就是tag
:param attrs: A dictionary of filters on attribute values. 用于限定的属性
:param recursive: If this is True, find() will perform a
recursive search of this PageElement's children. Otherwise, only the direct children will be considered.
:param limit: Stop looking after finding this many results. :kwargs: A dictionary of filters on attribute values.
:return: A PageElement.
:rtype: bs4.element.Tag | bs4.element.NavigableString
注意:
1. find的返回结果也是soup类型,所以可以迭代,一步步逼近目标。
2. recursive默认是FALSE,防止抓取到过多的信息。除非没什么干扰项
3. find只会返回自上而下找到的第一个。
3.soup.find_all()
爬虫大部分情况是在信息比较丰富的网页上批量的爬取数据。
所以find有很大的局限性。这个时候就需要find_all
和上面的find基本一致,除了返回的是一个列表之外。。。
见下面实操。
三、实操
为了避免反复爬取所以我们保存到文件中。
html_text = rep.text.encode('iso-8859-1').decode('gbk')
with open("shouye.txt","w",encoding="gbk") as outfile:
outfile.write(html_text)
with open("shouye.txt","r",encoding="gbk") as infile:
html_text=infile.read()
然后注释掉爬取的部分。
目标分析
<h1>修真聊天群</h1>
<p>作 者:圣骑士的传说</p>
<p>状 态:连载</p>
<p>动 作:<a href="#footer" style="color:red;">直达底部</a> <a href="javascript:addBookCase('1852');" rel="nofollow" style="color:red;">加入书架</a>
<p>最后更新:2020-08-10 11:24:43</p>
<p>最新章节:<a href="/1_1852/577127462.html">新书上传啦,《万界点名册》</a></p>
定位目标
工具是有限的,但是组合是无限的
定位的目的是为了快速的实现唯一性。
<div id="book">
<div class="path"><div class="p"><a href="/">笔趣阁</a> > <a href="/1_1852/">修真聊天群最新章节</a></div></div>
<div id="maininfo">
<div id="fmimg"><img alt="修真聊天群" src="/files/article/image/1/1852/1852s.jpg" width="120" height="150" onerror="this.src='/images/nocover.jpg'" /></div>
<div id="info">
<h1>修真聊天群</h1>
<p>作 者:圣骑士的传说</p>
<p>状 态:连载</p>
<p>动 作:<a href="#footer" style="color:red;">直达底部</a> <a rel="nofollow" href="javascript:addBookCase('1852');" style="color:red;">加入书架</a>
<p>最后更新:2020-08-10 11:24:43</p>
<p>最新章节:<a href="/1_1852/577127462.html">新书上传啦,《万界点名册》</a></p>
根据观察。我们id属性为book的div是唯一的。所以我们可以从这里开始。
 代表空格键,转义了而已。
实际上可以更进一步从这里开始。甚至可以直接用id。但是为了展示一下层层递进的定位方式。。。
没有困难,就要创造困难!!!
print(soup.find("div",attrs={"id":"book"}).find("div",attrs={"id":"info"})) # 递进的写法
print(soup.find_all("div",attrs={"id":"info"})) # 直接的写法
# find_all的结果 find的结果没有列表!!!
[<div id="info">
<h1>修真聊天群</h1>
<p>作 者:圣骑士的传说</p>
<p>状 态:连载</p>
<p>动 作:<a href="#footer" style="color:red;">直达底部</a> <a href="javascript:addBookCase('1852');" rel="nofollow" style="color:red;">加入书架</a>
<p>最后更新:2020-08-10 11:24:43</p>
<p>最新章节:<a href="/1_1852/577127462.html">新书上传啦,《万界点名册》</a></p>
</p></div>]
我想说的是find返回的还是soup可以一直在后面追加,就像从树的根节点到叶结点的过程。每一次find都相当于路径
显然这个路径是可以跳步的。只要思路好!!!
接下来更进一步!
字符串提取
如何将作者打印出来?
我们以作者为例
content = soup.find("div",attrs={"id":"book"}).find("div",attrs={"id":"info"}).find('p').string
print(content.split(":")) # 注意这个冒号
author = re.findall(r"作\xa0\xa0\xa0\xa0者:(.*)",content)[0]
print(author)
# 结果
['作\xa0\xa0\xa0\xa0者', '圣骑士的传说']
['圣骑士的传说']
还是很容易写错的。比如中间的空格符因为编码不一样所以可能匹配不到。
作 者,中间四个加空格就不行。
还有冒号也有中英文的区别。
\xa0 是不间断空白符
我们通常所用的空格是 \x20 ,是在标准ASCII可见字符 0x20~0x7e 范围内。
而 \xa0 属于 latin1 (ISO/IEC_8859-1)中的扩展字符集字符,代表空白符nbsp(non-breaking space)
' '.join(v.split())# 是用这个去转化然后处理,相当于换成了一般的空格。
四、总结
剩下的几个信息,大同小异,我相信留给诸位并不是很难。(用find_all)
还记得一开始,保存HTML到文件,然后用记事本打开吗?
用记事本打开的小伙伴基本是要翻车的。。。没错,我在误导你,就是这么邪恶。
记事本往往不会很好的显示格式或者空字符等等。但是这对我们定位信息是大忌。
推荐使用notepad++。
小而美的软件值得拥有。
链接:https://pan.baidu.com/s/19xovb6z086ycmbB_zc4siw
提取码:fmg5
仅仅这一个实例是不够的。
下一讲,是关于章节标题的爬取以及处理。