网页爬取练习:统计指定class的div数量异常,实际更多却仅返回1
嘿,作为刚入门web scraping时踩过不少坑的人,这种情况我太懂了!浏览器里明明能看到好几个目标div,但用len()统计只返回1个,大概率是下面这几个原因之一,咱们一个个来排查:
1. 页面内容是JavaScript动态加载的
这是最常见的原因!你用urllib.request.urlopen()拿到的是服务器返回的原始HTML代码,但很多现代网站会用JS在页面加载后动态渲染内容——比如滚动加载、AJAX请求获取数据再插入页面。浏览器里看到的那些div,其实是JS运行后才生成的,原始HTML里可能只有一个空的容器div,所以BeautifulSoup自然只能找到1个。
解决方案:用能执行JS的工具爬取
推荐用Selenium(上手简单)或者Playwright,它们能模拟真实浏览器加载页面,等JS执行完成后再获取完整的HTML。举个Selenium的例子:
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 from bs4 import BeautifulSoup as soup my_url = 'random_url' # 初始化Chrome浏览器(需提前安装对应版本的chromedriver) driver = webdriver.Chrome() driver.get(my_url) # 等待目标元素加载完成(最多等10秒,直到至少2个目标div出现) try: WebDriverWait(driver, 10).until( EC.presence_of_all_elements_located((By.CLASS_NAME, '你的目标class名')) ) finally: # 获取渲染后的完整HTML page_html = driver.page_source driver.quit() page_soup = soup(page_html, "html.parser") target_divs = page_soup.find_all('div', class_='你的目标class名') print(len(target_divs)) # 现在应该能得到正确数量了
2. BeautifulSoup的解析器使用错误
看你代码里写的soup(page_html, "html.pa..."),应该是想写"html.parser"吧?如果解析器拼写错误或者选择不合适,可能会导致HTML结构解析混乱,把多个div识别成一个。
解决方案:确认解析器正确
推荐用"html.parser"(Python内置,无需额外安装)或者"lxml"(解析速度更快,需要先pip install lxml)。修正后的初始化代码:
page_soup = soup(page_html, "html.parser") # 或者用lxml(需先安装) # page_soup = soup(page_html, "lxml")
3. 目标class名称匹配错误
有时候浏览器里看到的class可能包含多个值(比如class="product-item featured"),如果你只写了其中一个,或者拼写、大小写不对,都会导致匹配不全。另外,BeautifulSoup里用class_参数时,多个class值要写成完整字符串(比如class_="product-item featured"),或者用CSS选择器更精准。
解决方案:用CSS选择器匹配更可靠
用select()方法配合CSS选择器,能准确匹配多class的元素:
# 匹配同时包含product-item和featured类的div target_divs = page_soup.select('div.product-item.featured') print(len(target_divs))
4. 目标div嵌套在iframe中
如果你的目标div是在页面的iframe里,urllib只会拿到主页面的HTML,iframe里的内容需要单独请求。
解决方案:单独爬取iframe的内容
先找到iframe的src属性,然后请求这个URL:
from urllib.request import urlopen as uReq from urllib.parse import urljoin from bs4 import BeautifulSoup as soup my_url = 'random_url' uClient = uReq(my_url) page_html = uClient.read() uClient.close() page_soup = soup(page_html, "html.parser") iframe = page_soup.find('iframe') if iframe and 'src' in iframe.attrs: # 处理相对路径,拼接成完整URL iframe_url = urljoin(my_url, iframe['src']) uClient_iframe = uReq(iframe_url) iframe_html = uClient_iframe.read() uClient_iframe.close() iframe_soup = soup(iframe_html, "html.parser") target_divs = iframe_soup.find_all('div', class_='你的目标class名') print(len(target_divs))
先从这几个方向排查,应该能解决问题啦!
内容的提问来源于stack exchange,提问作者H D

