Python 环境加载中…

BeautifulSoup 基础

3 道练习题·预计 50 分钟·做对一题解锁下一段

完整通读本章 →

教学 01 / 08· 已读

前言

上一章,咱们用 find() 和切片,从网页里抠出了一个书名。办法是能用,可是费劲,网页稍微一改,代码就得跟着改。

有没有更省事的办法呢?这一章就请出专门解析 HTML 的工具:BeautifulSoup。它能把一大段 HTML 变成一棵可以随意翻找的树。你只要告诉它「找 class="price" 的标签」,它就把价格交到你手上。而且上一章学的 CSS 选择器,在这里直接就能用。

顺便说一句,BeautifulSoup 这个名字,来自《爱丽丝漫游奇境》里的一首歌。它不是 Python 自带的,在自己电脑上要装 beautifulsoup4 这个包,怎么装第 10 章会讲;在网页里,它已经准备好了。

BeautifulSoup 的方法不少,学的时候别想着一口气全记住。常用的其实就那么几个:find() 、find_all() 、select() 、select_one() 、get_text() 。先把这几个用熟,其他的遇到了再查。

学这一章之前,需要先学完 爬虫课第 3 章 ,认识 HTML 的标签、属性和 CSS 选择器。

目录

这一章会学到:

  • 一、把网页交给 BeautifulSoup——第一碗汤
  • 二、find() 和 find_all() ——按标签名和属性找
  • 三、select() 和 select_one() ——用 CSS 选择器找
  • 四、拿到标签以后——取文字、取属性、顺着树找
  • 五、常见坑
  • 六、自己查一次文档——get_text() 还能怎么用
  • 七、小结与回看

学完这一章,你能用 BeautifulSoup 从一个网页里准确地取出想要的文字和链接。

教学 02 / 08· 已读

一、把网页交给 BeautifulSoup

BeautifulSoup 到底有多省事?咱们拿上一章硬抠过的那个书名来比一比,用 BeautifulSoup 再取一次:

Python· 可在网页运行
import requests
from bs4 import BeautifulSoup

html = requests.get('https://learn-py.org/lab/bookstore/books/12/').text
soup = BeautifulSoup(html, 'html.parser')
print(soup.title.get_text())
print(soup.h2.get_text())

输出的结果:

文本
色彩的力量 · 两点书店
色彩的力量

上一章切了好几刀才拿到的书名,这里一行就取出来了。代码里有几样新东西,咱们一行一行地看:

  • from bs4 import BeautifulSoup :包的名字叫 beautifulsoup4 ,导入的时候写 bs4 。
  • BeautifulSoup(html, 'html.parser') :把 HTML 字符串交给它,第二个参数说明用哪个解析器。html.parser 是 Python 自带的,不用另外安装。得到的对象,大家习惯叫它 soup 。
  • soup.title :网页里第一个 <title> 标签。soup.h2 也是同样的道理,是第一个 <h2> 。
  • .get_text() :取出标签里的文字。

soup.标签名 这种写法很方便,可它有两个毛病:一是只能找到第一个,页面上有好几个同名的标签时,后面的就拿不到了;二是没法指定 class。

那么,要找得准,该怎么办呢?这就要用下面几节的方法了。

教学 03 / 08

二、find() 和 find_all()

先说 find() 。它可以按标签名和属性来找,返回第一个对得上的标签。比如要找详情页里的价格:

Python· 可在网页运行
import requests
from bs4 import BeautifulSoup

html = requests.get('https://learn-py.org/lab/bookstore/books/12/').text
soup = BeautifulSoup(html, 'html.parser')
price = soup.find('td', class_='price')
print(price)
print(price.get_text())

输出的结果:

文本
<td class="price">¥64.50</td>
¥64.50

find('td', class_='price') 的意思是:找 class 是 price 的 td 标签。直接打印找到的标签,看到的是整段 HTML;加上 get_text() ,才是里面的文字。

另外注意,class_ 后面多了一个下划线。为什么要加,第五节「常见坑」里会讲。

find() 只给第一个。那要是想要一页里所有的价格呢?这就要用 find_all() ,它返回所有对得上的标签,放在一个列表里:

Python· 可在网页运行
import requests
from bs4 import BeautifulSoup

html = requests.get('https://learn-py.org/lab/bookstore/').text
soup = BeautifulSoup(html, 'html.parser')
prices = soup.find_all('p', class_='price')
print(len(prices))
for p in prices[:3]:
    print(p.get_text())

输出的结果:

文本
20
¥104.40
¥42.70
¥56.20

一页 20 本书,就找到了 20 个价格。拿到的是列表,所以用 for 一个一个地取出来,这里只打印了前 3 个。

除了 class_ ,其他属性也可以拿来找。比如每本书卡片上的 data-id ,记着这本书的编号。要按编号找书,就把属性写成字典,交给 attrs :

Python· 可在网页运行
import requests
from bs4 import BeautifulSoup

html = requests.get('https://learn-py.org/lab/bookstore/').text
soup = BeautifulSoup(html, 'html.parser')
card = soup.find('article', attrs={'data-id': '5'})
print(card.find('h3').get_text())

输出的结果:

文本
实战学数据分析

为什么不像 class_ 那样,直接写成参数呢?因为 data-id 中间有个减号,没法写成 data-id='5' 这样的参数,只能放进 attrs 字典里。

这段代码里还有一个细节:card.find('h3') 是在 card 里面找,而不是在整个网页里找。先找到一本书,再在这本书里找书名,这是后面抓列表页的基本套路。

下面先做一道练习,从详情页里取出书名、价格和库存。

练习 1 / 3从详情页取书名、价格和库存题目有问题?

取回编号 30 这本书的详情页,用 BeautifulSoup 取出书名(h2.title )、价格(td.price )和库存(td.stock ),打印在同一行,用空格隔开。find() 和 select_one() 都可以用。

运行后的输出应该是:

文本
图标的秘密 ¥47.30 18 本
main.py
可编辑
做对当前题解锁下一段 ·03

推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai

学习目录