Python爬虫 - 专栏链接
手把手教你如何入门,如何进阶。
目录
1. BeautifulSoup是什么?
我们先熟悉下爬虫的四个步骤:1、获取数据。2、解析数据。3、提取数据。4、储存数据。
第1关的requests
库帮我们搞定了爬虫第1步——获取数据;第2关的HTML知识,是进行爬虫必不可少的背景知识,能辅助我们解析和提取数据。
而本关学习目标:学会使用 BeautifulSoup
解析和提取网页中的数据。
使用 BeautifulSoup
库 前需要先安装,可以通过在命令行中输入:
pip install beautifulsoup4
2. BeautifulSoup怎么用?
2.1 解析数据
我们以豆瓣读书 Top250 为例,它的网址是:https://book.douban.com/top250。
我们来看看如何将其网页源代码解析成 BeautifulSoup 对象:
import requests
from bs4 import BeautifulSoup
# 反爬策略之一,下一关重点说明反爬
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0'
}
res = requests.get('https://book.douban.com/top250', headers=headers)
soup = BeautifulSoup(res.text, 'html.parser')
注意:这里代码中多了一串代码,headers数组,这是反爬策略中的一种,下一关重点说明,如果不加这个数据,爬取不到我们要的数据。headers的作用是:伪装成浏览器,去访问该网页地址,这个数据可以通用的,可以去网上任意找个别人的,也可以自己打开浏览器查看,如下图:
我们通过 from bs4 import BeautifulSoup 语句导入 BeautifulSoup,然后使用 BeautifulSoup(res.text, 'html.parser') 语句将网页源代码的字符串形式解析成了 BeautifulSoup 对象。
创建 BeautifulSoup 对象时需要传入两个参数,第一个参数是要解析的 HTML 文本,即网站源代码的字符串形式(res.text)。第二个参数是解析 HTML 的解析器,html.parser 是 Python 中内置的解析器,较为简单方便,本课程中都将使用它。
2.2 提取数据
res = requests.get('https://book.douban.com/top250', headers=headers)
print(type(res.text))
# 输出:<class 'str'> 字符串
# 转为 BeautifulSoup 对象
soup = BeautifulSoup(res.text, 'html.parser')
print(type(soup))
# 输出:<class 'bs4.BeautifulSoup'> 对象
为什么我们要把网页的源代码转换为 BeautifulSoup 对象 呢?
因为 BeautifulSoup 对象 里的方法和属性有很多,我们只学习其中最常用的一些,这些足以应付大多数场景。等真正的入门后,可以自学那些更高阶的知识去解决更复杂的问题。
2.3 find() 方法 和 find_all() 方法
find()
与 find_all()
是 BeautifulSoup
对象的两个方法,它们可以匹配html的标签和属性,把BeautifulSoup对象里符合要求的数据都提取出来。
它俩的用法基本是一样的,区别在于,find()
只提取首个满足要求的数据,而find_all()
提取出的是所有满足要求的数据。
假设一个场景:爬取出豆瓣top250第一页的25本书的标题。
找数据技巧:鼠标右键标题红楼梦检查元素(火狐是检查,谷歌是审查),右侧查看红楼梦所在的html标签结构,因为有25本书,再看第二个标题活着检查元素,这个时候右侧的html结果都展开一下,把离数据最近的几个标签展开,如果有相同的div的class的值相同的,那么这个就是我们需要的元素结构。
find_all() 的场景:找到了数据所在的元素结构,直接看代码:
import requests
from bs4 import BeautifulSoup
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0'
}
res = requests.get('https://book.douban.com/top250', headers=headers)
soup = BeautifulSoup(res.text, 'html.parser')
# 前面的代码补上下列代码,注意这里用的是 find_all方法,获取多个元素结构
items = soup.find_all('div',class_='pl2') # 提取所有div标签满足 class属性值为pl2的标签,注意语法的class_ 有个下横杠,为了和class区别开
print(items)
打印结果是这样的(这里的数据是div的类属性class等于pl2的标签数据,下一步我们可以去除这些标签数据):
仔细看红框处,这里获取的数据是列表形式的,find_all()
提取出的是所有满足要求的数据。
find() 的场景:直接看代码:
import requests
from bs4 import BeautifulSoup
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0'
}
res = requests.get('https://book.douban.com/top250', headers=headers)
soup = BeautifulSoup(res.text, 'html.parser')
# find_all方法换成find方法后打印查看数据
items = soup.find('div',class_='pl2')
print(items)
打印结果是这样的:
打印的结果是字符串形式的,而且只有一条数据。
find_all() 方法 和 find() 方法的区别就是这样,根据实际数据用哪种方法。(我们这里需要用 find_all() 方法,因为要获取25本书的标题,而不是首个标题)
2.4 Tag标签 和 css 选择器
我们接着上面的代码继续往下,拿到我们要的25本书的标题数据。
因为我们用 find_all() 方法获得到的是列表,那么我们就循环:(第二行我们用到了 find() 方法了,因为数据在div属性class='pl2'下的首个a标签内)
for i in items:
tag = i.find('a')
print(tag)
# <a href="https://book.douban.com/subject/1007305/"onclick=""moreurl(this,{i:'0'})""title="红楼梦">红楼梦</a>
# <a href="https://book.douban.com/subject/4913064/"onclick=""moreurl(this,{i:'1'})""title="活着">活着</a>
# <a href="https://book.douban.com/subject/6082808/"onclick=""moreurl(this,{i:'2'})""title="百年孤独">百年孤独</a>
# ...
这样,我们就找到了所有书名的数据。此时返回的还是 Tag 对象。如果我们只想要书名和对应的链接呢?这就用到了 Tag 对象 的 text 属性和 HTML 属性名取值。
for i in items:
tag = i.find('a')
name = tag.text
link = tag['href']
print(name,link)
# 红楼梦 https://book.douban.com/subject/1007305/
# 活着 https://book.douban.com/subject/4913064/
# 百年孤独 https://book.douban.com/subject/6082808/
# ...
我们通过 Tag 对象 的 text 属性拿到了 a 标签里的文字内容,即 追风筝的人 等。然后我们通过和字典取值一样的方式,将 HTML 属性名 作为键,得到了对应属性的值。这里是以 href 属性为例,其他的 HTML 属性也同样可以。
我们通过多次调用 find() 或 find_all() 方法一层层地找到了我们需要的数据。你可能会问,有没有什么方法可以直接就找到我们需要的数据,而不用多次查找吗?
答案是肯定的,需要用到 CSS 选择器,这里简单介绍一下。
来看个例子感受一下它们的区别:
from bs4 import BeautifulSoup
html = '''
<div class="item">
<p class="book">红楼梦</p>
<div class="hot">
<p class="book">百年孤独</p>
</div>
</div>'''
soup = BeautifulSoup(html, 'html.parser')
print(soup.select('.item.book')) # 两个类选择器要有空格分开
# 输出:[]
print(soup.select('.item .book')) # 表示类item下的所有 类值为book的元素
# 输出:[<p class="book">红楼梦</p>, <p class="book">百年孤独</p>]
print(soup.select('.item > .book')) # 表示item下的第一个 类值为book的元素
# 输出:[<p class="book">红楼梦</p>]
CSS 选择器的语法还有很多,这里只介绍了些常用的,你如果对此感兴趣,可以自行深入了解。
了解了 CSS 选择器的基本语法后,我们来看看如何在 BeautifulSoup 中使用。
BeautifulSoup 对象 有一个 select() 方法,我们将 CSS 选择器 传进去即可直接找到我们需要的元素。上面查找在 class="pl2" 的 div 标签 里的 a 标签 的代码就可以这样写:
# items = soup.find_all('div',class_='pl2')
items = soup.select('.pl2 > a') # 类值为pl2下的第一个a标签
for i in items:
# tag = i.find('a')
# name = tag.text
name = i.text
# link = tag['href']
link = i['href']
print(name,link)
# 红楼梦 https://book.douban.com/subject/1007305/
# 活着 https://book.douban.com/subject/4913064/
# 百年孤独 https://book.douban.com/subject/6082808/
可以看到,我们一次性就将所有符合条件的 a 元素找了出来,同样的功能,代码变得更加简洁了。
对于对 CSS 选择器较为了解的人来说,使用 CSS 选择器的方法十分方便简洁。但即使不了解 CSS 选择器也没关系,我们还有简单好用的 find() 或 find_all() 方法,不是吗?
我们来总结一下 Tag 对象 的常用属性和方法:
知识点拓展:获取的数据存在换行,空格时,我们可以使用:1 .strip()去除首尾空格。2 .replace('\n','')去除换行为空白,.replace(' ','')去除所有字符串中的空格。
练习题
同学们,先自觉练习,答案在公众号,公众号回复暗号【答案】即可。
1. 用来解析网页的 Python 库是?
A.requests
B.BeautifulSoup
C.range
D.html
2. 下列代码的运行结果是?
from bs4 import BeautifulSoup
html = '''
<div class="wrapper">
<p class="title">Python家庭</p>
<p class="desc">带你打开编程世界的大门</p>
</div>
'''
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('p')
print(tag)
A.<p class="title">Python家庭</p>
B.<p class="desc">带你打开扇贝世界的大门</p>
C.[<p class="title">Python家庭</p>, <p class="desc">带你打开编程世界的大门</p>]
3. 下列代码的运行结果是?
from bs4 import BeautifulSoup
html = '''
<div class="wrapper">
<p class="title">Python家庭</p>
<p class="desc">带你打开编程世界的大门</p>
</div>'''
soup = BeautifulSoup(html, 'html.parser')
tags = soup.find_all('p')
print(tags)
A.<p class="title">Python家庭</p>
B.<p class="desc">带你打开扇贝世界的大门</p>
C.[<p class="title">Python家庭</p>, <p class="desc">带你打开编程世界的大门</p>]
4. 下列代码的运行结果是?
from bs4 import BeautifulSoup
html = '''
<div class="wrapper">
<p class="title">Python家庭</p>
<p class="desc">带你打开编程世界的大门</p>
</div>'''
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find(class_="title")
print(tag.text)
A.Python家庭
B.带你打开编程世界的大门
C.<p class="title">Python家庭</p>
D.<p class="desc">带你打开编程世界的大门</p>
5. 代码实操:爬取 https://book.douban.com/top250 豆瓣书籍该页面下的书籍全部数据,如下图:
练习知识点:
方法1:find_all() 和 find() 方法搭配使用。
方法2:css选择器select()的使用。
先要自己动手练习喔,再去查看答案代码,答案代码两种方法都有。
联系我们,一起学Python吧
每周每日,分享Python实战代码,入门资料,进阶资料,基础语法,爬虫,数据分析,web网站,机器学习,深度学习等等。
微信群(关注「Python家庭」一起轻松学Python吧)
QQ 群(983031854)