Python 使用 BeautifulSoup 解析网页标题

79 阅读3分钟

import requests from bs4 import BeautifulSoup url='www.cdsf.org.cn/' s=requests.Session() s.trust_env=False html=s.get(url).text soup=BeautifulSoup(html) print(soup.title.string)

ChatGPT 说:

已思考 8s

燎然,这样有时能跑,但不稳,主要有 4 个坑:

  1. 没 UA:不少站看到 python-requests 会给“瘦页面”或直接拦。

  2. 没超时:默认无限等,卡住你不知道。

  3. 没指定解析器BeautifulSoup(html) 会猜解析器,容易出警告/不一致;建议显式 "html.parser"(或安装 lxml 后用它)。

  4. 直接 .title.string:只在 <title> 只有“单一纯文本子节点”时才有值,否则就是 None;稳妥写法用 get_text() 并先判空。

最小改动版(在你代码上修一下就行)

import requests
from bs4 import BeautifulSoup

url = "https://www.cdsf.org.cn/"
HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/139.0 Safari/537.36"
    )
}

s = requests.Session()
s.trust_env = False                           # 不继承系统代理
r = s.get(url, headers=HEADERS, timeout=(6,15), allow_redirects=True)
r.raise_for_status()

# 编码兜底(很多中文站声明不准)
if r.apparent_encoding and (not r.encoding or r.encoding.lower() == "iso-8859-1"):
    r.encoding = r.apparent_encoding

soup = BeautifulSoup(r.text, "html.parser")   # 显式解析器
title_tag = soup.find("title")
print(title_tag.get_text(strip=True) if title_tag else "未找到标题")

为啥你那段可能“看起来能跑”

  • 有的网站刚好不拦 UA、编码也正常、页面有标准 <title>,所以你能打印出标题;

  • 但一旦遇到编码写错、风控或 <title> 内混了子标签,你的代码就会翻车(None 或乱码)。

小技巧(排错时很有用)

print(r.status_code, r.url, r.encoding)   # 看状态/跳转/编码
print(len(r.text))                        # 页面很短多半是“瘦页面”

照这版改,你这一步就稳了。接下来我们可以把“标题解析”扩成:优先 <title>og:titletwitter:title<h1>,命中率更高。继续冲!💪

您说:

html.parser 是什么

ChatGPT 说:

已思考 10s

"html.parser"BeautifulSoup 使用的解析器名称,表示用 Python 标准库自带的 HTML 解析器来把一段 HTML 字符串“拆解 → 建树(DOM)”。有了树结构,你就能 find / select / get_text 去定位元素、拿文本和属性。

和其它解析器怎么选?

常见 3 个选项(把第二个参数换掉就行):

  • "html.parser"(你现在用的)

    • 优点:零依赖、安装最省事、稳定性尚可。

    • 缺点:速度和容错性一般,遇到很烂的 HTML 可能还原不完整。

  • "lxml"(推荐)

    • 优点最快、容错也强,解析结果稳定。

    • 缺点:需要安装 lxmlpip install lxml),首次装略慢。

  • "html5lib"

    • 优点容错最强,按浏览器 HTML5 规范修树,烂页面也能还原。

    • 缺点最慢,还需安装 html5lib

代码示例

from bs4 import BeautifulSoup

# 显式指定解析器(建议总是显式)
soup = BeautifulSoup(html, "html.parser")   # 零依赖
# soup = BeautifulSoup(html, "lxml")       # pip install lxml
# soup = BeautifulSoup(html, "html5lib")   # pip install html5lib

自动优先用 lxml,缺了就退回 html.parser

from bs4 import BeautifulSoup

try:
    import lxml  # 只为检测是否安装
    PARSER = "lxml"
except Exception:
    PARSER = "html.parser"

soup = BeautifulSoup(html, PARSER)

实战建议(给你当前项目)

  • pip install lxml,把解析器切到 "lxml",你的爬虫会更快更稳

  • 遇到“瘦页面/烂 HTML”解析不出结构,再临时切 "html5lib" 尝试。

  • 一定显式指定解析器:不同环境的默认值可能不同,显式能避免不可预期差异。

一句话记忆:
html.parser = 自带解析器,够用但一般 → 优先用 lxml,必要时 html5lib 救场。

您说:

import requests from bs4 import BeautifulSoup url='www.cdsf.org.cn/' s=requests.Session() s.trust_env=False r=s.get(url,timeout(4,10)).text soup=BeautifulSoup(r,"html.parser") print(soup.title.string)

ChatGPT 说:

已思考 26s

燎然,你这段报错的核心是这行写错了:

r = s.get(url,timeout(4,10)).text

timeout(4,10) 像是在“调用一个名为 timeout 的函数”,而不是把 timeout 参数 传给 get。正确写法是关键字参数

最小修复版(直接能跑)

import requests
from bs4 import BeautifulSoup

url = "https://www.cdsf.org.cn/"
s = requests.Session()
s.trust_env = False

resp = s.get(url, timeout=(4, 10))      # ✅ 用等号,(连接超时, 读取超时)
resp.raise_for_status()

soup = BeautifulSoup(resp.text, "html.parser")
print(soup.title.get_text(strip=True) if soup.title else "未找到标题")

建议的稳健版(加 UA + 编码兜底)

import requests
from bs4 import BeautifulSoup

url = "https://www.cdsf.org.cn/"
HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/139.0 Safari/537.36"
    )
}

with requests.Session() as s:
    s.trust_env = False
    r = s.get(url, headers=HEADERS, timeout=(4,10), allow_redirects=True)
    r.raise_for_status()

    # 编码兜底(很多中文站写成 ISO-8859-1)
    if r.apparent_encoding and (not r.encoding or r.encoding.lower() == "iso-8859-1"):
        r.encoding = r.apparent_encoding

    soup = BeautifulSoup(r.text, "html.parser")
    print(soup.title.get_text(strip=True) if soup.title else "未找到标题")