如何用Python+bs4读取完整网页?requests仅返回页面前半部分
问题根因
拿不到完整<body>内容的核心原因有两个:
- 站点存在基础反爬校验:原生
requests默认携带的User-Agent等请求头会标识自身为爬虫程序,站点识别后仅返回不完整的<head>片段,拒绝下发正文资源 - 词条内容为JS动态渲染:页面初始返回的HTML骨架中不包含
<terms>节点下的术语、释义内容,需要前端执行JS逻辑、拉取接口数据后才会把目标内容插入DOM。直接保存静态HTML不会触发JS执行,这也是浏览器“另存为HTML”拿不到完整内容的原因。
解决方案
按实现成本从低到高选择:
方案1:补全浏览器请求头,直连尝试获取
先模拟真实浏览器的请求头,绕过最基础的UA校验,部分场景下可以直接拿到完整内容:
import requests from bs4 import BeautifulSoup target_url = "https://dictionary.apa.org/caffeine-intoxication" # *提示:请求头可以从自己浏览器的F12网络面板中复制同域名请求的头信息,避免被识别为爬虫* request_headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", "Referer": "https://dictionary.apa.org/" } response = requests.get(target_url, headers=request_headers, timeout=15) response.encoding = "utf-8" # 检查返回内容是否包含目标<terms>标签 if "<terms>" in response.text: soup = BeautifulSoup(response.text, "html.parser") for term_node in soup.select("terms term"): term = term_node.select_one("hw").get_text(strip=True) definition = term_node.select_one("dd").get_text(strip=True, separator=" ") print(f"术语:{term}\n释义:{definition}\n---") else: print("直连未拿到正文,换无头浏览器方案")
方案2:使用无头浏览器模拟真实访问,等待JS渲染完成后提取内容
如果方案1失效,说明站点有更严格的反爬(比如TLS指纹校验、JS验证、内容完全异步加载),直接用浏览器内核渲染页面,等所有资源加载、JS执行完成后再提取DOM,能拿到和手动打开浏览器完全一致的内容:
- 先安装依赖:
pip install playwright playwright install chromium
- 爬取代码:
import time import random from playwright.sync_api import sync_playwright from bs4 import BeautifulSoup def crawl_apa_dictionary(url): with sync_playwright() as p: # headless=False可以弹出浏览器窗口,遇到人机验证时可以手动操作 browser = p.chromium.launch(headless=True) page = browser.new_page( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" ) page.goto(url, wait_until="networkidle") # 等待术语节点加载完成,最长等10秒 page.wait_for_selector("terms term", timeout=10000) full_html = page.content() browser.close() soup = BeautifulSoup(full_html, "html.parser") result = [] for term_node in soup.select("terms term"): term = term_node.select_one("hw").get_text(strip=True) definition = term_node.select_one("dd").get_text(strip=True, separator=" ") result.append((term, definition)) return result if __name__ == "__main__": test_url = "https://dictionary.apa.org/caffeine-intoxication" term_list = crawl_apa_dictionary(test_url) for word, desc in term_list: print(f"术语:{word}\n释义:{desc}\n---")
爬取注意事项
- 控制请求频率,每次请求间隔加2-5秒的随机延时,避免IP被封禁
- 爬取内容仅可用于个人学习,不要批量传播受版权保护的词典内容
- 如果遇到人机验证,将
headless=True改为headless=False手动通过验证后即可正常爬取
内容的提问来源于stack exchange,提问作者Andrey Glinsky
相关产品推荐
相关产品推荐

