BeautifulSoup 基础
3 道练习题·预计 50 分钟·做对一题解锁下一段
前言
上一章,咱们用 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 从一个网页里准确地取出想要的文字和链接。
一、把网页交给 BeautifulSoup
BeautifulSoup 到底有多省事?咱们拿上一章硬抠过的那个书名来比一比,用 BeautifulSoup 再取一次:
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。
那么,要找得准,该怎么办呢?这就要用下面几节的方法了。
二、find() 和 find_all()
先说 find() 。它可以按标签名和属性来找,返回第一个对得上的标签。比如要找详情页里的价格:
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.50find('td', class_='price') 的意思是:找 class 是 price 的 td 标签。直接打印找到的标签,看到的是整段 HTML;加上 get_text() ,才是里面的文字。
另外注意,class_ 后面多了一个下划线。为什么要加,第五节「常见坑」里会讲。
find() 只给第一个。那要是想要一页里所有的价格呢?这就要用 find_all() ,它返回所有对得上的标签,放在一个列表里:
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 :
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 里面找,而不是在整个网页里找。先找到一本书,再在这本书里找书名,这是后面抓列表页的基本套路。
下面先做一道练习,从详情页里取出书名、价格和库存。
取回编号 30 这本书的详情页,用 BeautifulSoup 取出书名(h2.title )、价格(td.price )和库存(td.stock ),打印在同一行,用空格隔开。find() 和 select_one() 都可以用。
运行后的输出应该是:
图标的秘密 ¥47.30 18 本推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai