使用BeautifulSoup和Selenium无法获取网页完整HTML内容的技术求助
解决方案:爬取Lloyd's List港口目录页面的完整内容
我碰到过不少这类动态内容加载+反爬检测的场景,咱们一步步拆解问题,针对性解决:
一、先搞定BeautifulSoup爬取不完整的问题:模拟真实浏览器请求
直接用requests.get()拿到的是服务器初始返回的静态HTML,而页面主体内容大概率是后续通过JS动态加载的,或者需要携带正确的会话信息(Cookie、请求头)才能获取完整渲染的内容。
操作步骤:
- 打开浏览器开发者工具(F12),切换到Network标签,刷新目标页面,找到主文档请求(就是URL为
https://directories.lloydslist.com/var/recordset/65237/pos/11的那条请求) - 复制该请求Request Headers里的
User-Agent、Cookie、Referer等关键字段 - 用
requests.Session()模拟这个请求,确保携带所有必要的头信息:
import requests from bs4 import BeautifulSoup session = requests.Session() headers = { 'User-Agent': '替换成你的浏览器真实User-Agent', 'Cookie': '从开发者工具复制的完整Cookie字符串', 'Referer': 'https://directories.lloydslist.com/' } url = "https://directories.lloydslist.com/var/recordset/65237/pos/11" response = session.get(url, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') # 现在检查body的ID和内容是否完整 print(soup.body.get('id'))
⚠️ 注意:Cookie可能会过期,需要定期更新;如果网站需要登录才能访问,得先模拟登录流程获取有效Cookie。
二、优化Selenium配置,绕过反爬检测
如果Selenium也拿不到完整内容,基本是网站识别出了自动化浏览器。可以通过以下配置让Selenium更贴近真实浏览器:
1. 禁用自动化标识+配置真实请求头
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC options = webdriver.ChromeOptions() # 禁用自动化扩展和标识 options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) # 设置真实的User-Agent options.add_argument("user-agent=替换成你的浏览器真实User-Agent") # 可选:启用无头模式(不需要可视化页面时) # options.add_argument("--headless=new") driver = webdriver.Chrome(options=options) # 进一步隐藏webdriver属性 driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") url = "https://directories.lloydslist.com/var/recordset/65237/pos/11" driver.get(url) # 显式等待页面关键元素加载完成(比如港口列表的容器,替换成你在浏览器里看到的类名) wait = WebDriverWait(driver, 10) port_container = wait.until(EC.presence_of_element_located((By.CLASS_NAME, '港口列表容器类名'))) # 现在获取完整的页面源码 page_source = driver.page_source soup = BeautifulSoup(page_source, 'html.parser') # 提取港口信息(替换成实际的元素选择器) ports = soup.find_all('div', class_='港口项的类名') for port in ports: print(port.get_text(strip=True)) driver.quit()
2. 模拟人类交互(可选)
有些网站需要滚动页面才会加载全部内容,可以添加滚动代码:
# 滚动到页面底部,触发内容加载 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
三、寻找隐藏的API接口(最高效的方案)
很多动态渲染的网站会通过AJAX请求获取数据,你可以在开发者工具的Network标签里,切换到XHR或Fetch分类,查找返回港口数据的API接口。比如可能有类似https://directories.lloydslist.com/api/records/65237?pos=11的请求,直接返回JSON格式的数据,比爬HTML高效得多。
操作步骤:
- 刷新页面后,查看XHR请求列表,找到返回港口数据的请求
- 复制该请求的URL、Headers和参数
- 用
requests直接请求API并解析JSON:
import requests headers = { 'User-Agent': '替换成你的浏览器真实User-Agent', 'Cookie': '复制的Cookie', 'Accept': 'application/json' } api_url = "找到的API接口URL" response = requests.get(api_url, headers=headers) port_data = response.json() # 提取港口位置信息(根据实际的JSON结构调整字段名) for item in port_data['records']: print(f"港口名称: {item['name']}, 位置: {item['location']}")
四、避坑提醒
- 不要频繁请求,避免被封IP,可以添加请求间隔(比如
time.sleep(2)) - 严格遵守网站的
robots.txt协议,不要爬取禁止访问的内容 - 如果网站需要登录,先完成登录流程保存有效Cookie,再进行爬取
内容的提问来源于stack exchange,提问作者Alex Matthews
相关产品推荐
相关产品推荐

