BS4的find_all()未捕获全部内容:IMDb导演作品提取异常求助
问题:抓取IMDB导演肯·洛奇作品时仅得到15条结果,而非全部56条?
我尝试提取导演肯·洛奇(Ken Loach)的所有导演作品,已知他共有56部相关作品。我用find()定位到了目标<ul>标签,但调用find_all()提取其下<li>标签时,只得到15条结果,不是预期的56条。我的代码如下:
url="https://www.imdb.com/name/nm0516360/?ref_=nv_sr_srsg_0" hdr = {'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Mobile Safari/537.36'} resp=requests.get(url, headers=hdr) html=resp.content soup=BeautifulSoup(html, "html.parser") uls=soup.find('ul', 'ipc-metadata-list ipc-metadata-list--dividers-between ipc-metadata-list--base') films=uls.find_all('li', 'ipc-metadata-list-summary-item ipc-metadata-list-summary-item--click sc-139216f7-1 fFMbUG') print(len(films))
我哪里出错了?注:我是网页抓取新手,正在学习相关技术。
原因与解决方法
核心问题1:页面懒加载
IMDB的人物作品页面采用懒加载机制——初始请求返回的HTML里只包含前15条作品,剩下的内容需要用户滚动页面到下方时,才会通过异步请求加载更多数据。直接用requests获取静态HTML自然只能拿到初始的15条。
核心问题2:依赖不稳定的动态class
你用的sc-139216f7-1 fFMbUG这类class是IMDB动态生成的,随时可能变化,一旦网站更新样式,你的选择器就会失效。应该改用更稳定的定位方式,比如元素的data-testid属性或者结构关系。
解决办法
方法1:用Selenium模拟浏览器加载全部内容
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 import time url = "https://www.imdb.com/name/nm0516360/?ref_=nv_sr_srsg_0" driver = webdriver.Chrome() # 需要提前安装对应版本的ChromeDriver driver.get(url) # 模拟滚动到底部,触发加载更多 last_height = driver.execute_script("return document.body.scrollHeight") while True: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(2) # 等待页面加载 new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height # 用稳定的选择器抓取所有作品li wait = WebDriverWait(driver, 10) ul_element = wait.until(EC.presence_of_element_located((By.DATA_TEST_ID, "filmography"))) films = ul_element.find_elements(By.CSS_SELECTOR, "li.ipc-metadata-list-summary-item") print(len(films)) # 现在应该能拿到全部56条 driver.quit()
方法2:改用稳定的静态选择器(仅解决class失效问题,无法处理懒加载)
如果暂时不想用Selenium,先把选择器改成更可靠的,比如用data-testid或者结构选择器:
# 替换原有的ul和films定位代码 uls = soup.find('ul', {'data-testid': 'filmography'}) # 不依赖动态class,只保留基础的稳定class films = uls.find_all('li', 'ipc-metadata-list-summary-item')
不过这种方法还是只能拿到初始的15条,要获取全部内容还是得处理懒加载。
内容的提问来源于stack exchange,提问作者noob87
相关产品推荐
相关产品推荐

