4、Python爬虫基础:Requests库的使用、BeautifulSoup解析HTML、XPath与CSS选择器、数据提取实战

好,咱们进入爬虫实战环节。说实话,很多新手一上来就想着搞分布式、搞反爬,其实没必要。你想想看,一个连网页都拿不下来的人,谈什么反爬?

这一章,我带你从零开始,把爬虫最核心的四个技能点打扎实。分别是:发请求、解析页面、定位元素、提取数据。嗯,就这么简单,但足够你应付80%的日常需求了。

4.1 Requests库:你的网络触手

Requests 是 Python 里最优雅的 HTTP 库,没有之一。我当年用 urllib 的时候,每次写请求都要手动拼接参数、处理编码,烦得要死。后来换了 Requests,感觉整个世界都清净了。

4.1.1 安装与基本请求

pip install requests

装好之后,发一个 GET 请求有多简单?看代码:

import requests

url = "https://httpbin.org/get"
response = requests.get(url)
print(response.status_code)  # 200
print(response.text)         # 响应内容(字符串)
print(response.json())       # 如果返回JSON,直接解析成字典

我个人习惯,每次写完请求先打印 status_code。为什么?因为很多问题出在请求本身,比如 URL 写错了、服务器拒绝了。看一眼状态码,心里就有底了。

小技巧: 如果遇到乱码,试试 response.encoding = 'utf-8'。我在爬某个老网站时遇到过,它返回的响应头里编码声明是错的,手动指定一下就正常了。

4.1.2 带参数的请求

很多时候,我们需要在 URL 后面加参数。比如搜索、翻页。Requests 处理这个特别优雅:

params = {
    "q": "Python爬虫",
    "page": 1
}
response = requests.get("https://httpbin.org/get", params=params)
print(response.url)  # 自动拼接成完整URL

你想想看,如果手动拼接,还得处理特殊字符的转义。用 params 参数,这些脏活累活 Requests 全帮你干了。

4.1.3 请求头与超时

有些网站会检查请求头,比如 User-Agent。不加的话,可能直接返回 403 拒绝访问。我刚开始学爬虫时就吃过这个亏,死活拿不到数据,后来发现是没伪装成浏览器。

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
response = requests.get(url, headers=headers, timeout=5)
注意: 一定要加 timeout 参数!我曾经写过一个爬虫,没设超时,结果某个请求卡住了,整个程序就挂在那里不动了。设个 5 秒、10 秒,既保护自己,也减轻对方服务器压力。

4.2 BeautifulSoup:HTML 解析利器

拿到网页源码之后,下一步就是解析它。BeautifulSoup 是我用得最多的解析库,因为它对新手特别友好。说白了,它就是把混乱的 HTML 变成一棵清晰的树,你想摘哪个节点就摘哪个。

4.2.1 安装与基本用法

pip install beautifulsoup4 lxml

注意,我建议同时安装 lxml 解析器。BeautifulSoup 默认用 Python 内置的解析器,速度慢,而且容错性差。lxml 是 C 语言写的,快得多。

from bs4 import BeautifulSoup

html = "<html><body><h1>Hello, World!</h1></body></html>"
soup = BeautifulSoup(html, "lxml")
print(soup.h1.text)  # 输出:Hello, World!

看到了吗?直接 soup.h1 就能拿到标签。BeautifulSoup 会自动补全缺失的标签,容错性极强。嗯,这一点在实际项目中特别有用,因为很多网站的 HTML 写得并不规范。

4.2.2 常用方法

我整理了一张表,把最常用的几个方法列出来,你直接照着用就行:

方法 作用 示例
find() 找到第一个匹配的标签 soup.find('div', class_='content')
find_all() 找到所有匹配的标签,返回列表 soup.find_all('a')
select() 用 CSS 选择器定位 soup.select('.item a')
.text 获取标签内的文本内容 soup.h1.text
.get() 获取标签的属性值 soup.a.get('href')
核心思路: 先用 find_allselect 定位到包含数据的容器,再逐个提取里面的文本和属性。千万别想着一步到位,拆开来做,逻辑更清晰。

4.3 XPath 与 CSS 选择器:精准定位

BeautifulSoup 的 find 方法虽然好用,但遇到复杂的嵌套结构时,写起来就有点啰嗦了。这时候,XPath 和 CSS 选择器就派上用场了。

4.3.1 XPath 基础

XPath 是一种在 XML/HTML 文档中查找信息的语言。它的语法很强大,但咱们只需要掌握几个核心的:

from lxml import etree

html = "<html><body><div class='item'><a href='link1'>链接1</a></div></body></html>"
tree = etree.HTML(html)

# 绝对路径
result = tree.xpath('/html/body/div/a/text()')  # ['链接1']

# 相对路径 + 属性过滤
result = tree.xpath('//div[@class="item"]/a/@href')  # ['link1']

# 通配符
result = tree.xpath('//*[@class="item"]')  # 所有class为item的元素

我个人习惯用 // 开头,因为不用关心具体的层级结构,直接按属性或标签名找就行了。你想想看,一个网页可能有几十层嵌套,用绝对路径写起来多累啊。

避坑指南: 我曾经在爬一个电商网站时,用 XPath 怎么都取不到数据。后来发现,页面是动态加载的,源代码里根本没有那些商品信息。记住,XPath 只能解析静态 HTML,动态内容得用 Selenium 或分析 Ajax 接口。

4.3.2 CSS 选择器

如果你熟悉前端,CSS 选择器可能更顺手。BeautifulSoup 和 lxml 都支持:

# 用 BeautifulSoup 的 select 方法
soup.select('.item a')        # class为item下的所有a标签
soup.select('#main > p')      # id为main的直接子元素p
soup.select('a[href^="http"]') # href以http开头的a标签

# 用 lxml 的 cssselect 方法
from lxml.cssselect import CSSSelector
sel = CSSSelector('.item a')
results = sel(tree)

嗯,这里有个小建议:能用 CSS 选择器就别用 XPath。为什么?因为 CSS 选择器更简洁,可读性更好。除非你需要用到 XPath 的高级功能,比如按文本内容定位、按位置索引等。

4.4 数据提取实战:从理论到代码

光说不练假把式。咱们拿一个真实的场景来练手:爬取一个新闻列表页,提取标题、链接和发布时间

4.4.1 完整代码示例

import requests
from bs4 import BeautifulSoup

# 1. 发请求
url = "https://example.com/news"
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers, timeout=5)
response.encoding = 'utf-8'

# 2. 解析页面
soup = BeautifulSoup(response.text, "lxml")

# 3. 定位数据容器
news_list = soup.select('.news-list .item')

# 4. 提取数据
for news in news_list:
    title = news.find('h2').text.strip()
    link = news.find('a').get('href')
    date = news.find('.date').text.strip()
    print(f"标题:{title} | 链接:{link} | 日期:{date}")

这个流程,说白了就是四步走:请求 → 解析 → 定位 → 提取。我做了这么多年爬虫,不管多复杂的项目,底层逻辑都是这四步。

4.4.2 常见问题与处理

  • 拿不到数据? 先打印 response.text 看看,是不是被反爬了,或者页面是动态加载的。
  • 提取结果为空? 检查选择器是否写对了。我建议先在浏览器开发者工具里验证一下选择器。
  • 数据有空白或换行?.strip() 清理一下。我每次提取文本都会加这个,已成习惯。
重要提醒: 爬虫不是万能的。有些网站有 robots.txt 限制,有些需要登录才能访问。请遵守网站的规则,不要频繁请求,不要爬取敏感数据。做一个有道德的爬虫工程师。

4.5 本章小结

这一章,咱们把爬虫最基础也最重要的四个工具过了一遍。Requests 负责拿数据,BeautifulSoup 负责解析,XPath 和 CSS 选择器负责定位,最后把数据提取出来。你想想看,是不是很简单?

下一章,我会带你深入爬虫的进阶技巧,包括处理动态页面、模拟登录、使用代理等。嗯,到时候你会发现,爬虫的世界远比你想象的精彩。

课后练习: 找一个你常看的新闻网站,用本章学到的知识,写一个爬虫提取首页的新闻标题和链接。遇到问题不要怕,先打印 response.text 看看,再一步步调试。相信我,写出来之后你会很有成就感。