Scrapy如何爬取无分页、点击加载更多的AJAX动态页面
爬取动态加载展商列表实现方案
你现有代码无法爬取全量数据的核心原因是:SeleniumRequest默认只等待初始页面加载完成就返回响应,没有执行「循环点击加载更多按钮直到所有内容加载完毕」的动作,因此只能拿到首屏的少量展商数据。
核心修改逻辑
- 初始页面加载完成后,直接获取绑定的Selenium webdriver实例,不直接使用初始response的选择器结果
- 编写循环判断逻辑:检测页面上的「Load More」按钮是否存在且可交互
- 若按钮存在:先滚动页面到按钮位置避免点击遮挡,点击按钮后等待新一批展商内容加载完成
- 若按钮不存在/处于禁用状态:说明全量展商已经加载完毕,退出循环
- 全量内容加载完成后,从webdriver当前渲染完成的页面源码中提取所有展商详情页链接,再按原有逻辑解析详情页字段即可
修改后可直接运行的代码
import scrapy from scrapy.http import Request from scrapy_selenium import SeleniumRequest from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException import time class TestSpider(scrapy.Spider): name = 'test' # 超时、点击间隔可根据网络情况调整 wait_timeout = 10 click_wait = 2 def start_requests(self): yield SeleniumRequest( url="https://aaos22.mapyourshow.com/8_0/explore/exhibitor-gallery.cfm?featured=false", wait_time=3, callback=self.parse, dont_filter=True ) def parse(self, response): # 获取当前绑定的webdriver实例 driver = response.request.meta['driver'] wait = WebDriverWait(driver, self.wait_timeout) # 循环点击加载更多按钮 while True: try: # 定位加载更多按钮,若选择器不匹配可在浏览器开发者工具中核对替换 load_more_btn = wait.until( EC.element_to_be_clickable((By.CSS_SELECTOR, 'button.btn-load-more, button[data-testid="load-more"]')) ) # 滚动到按钮位置,避免元素遮挡导致点击失败 driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", load_more_btn) time.sleep(0.5) # 点击按钮 load_more_btn.click() # 等待新内容加载 time.sleep(self.click_wait) except (TimeoutException, NoSuchElementException): # 找不到可点击的加载更多按钮,说明所有内容加载完成 break # 所有展商加载完成后,重新获取当前页面的完整源码构造选择器 full_page = scrapy.Selector(text=driver.page_source) # 提取所有展商详情链接 exhibitor_links = full_page.xpath("//h3[@class='card-Title break-word f3 mb1 mt0']//a/@href").extract() for link in exhibitor_links: url = response.urljoin(link) yield Request(url, callback=self.parse_book) def parse_book(self, response): title = response.css(".mr3-m::text").get() address = response.css(".showcase-address::text").get() if address: address = address.strip() website = response.xpath("//li[@class='dib ml3 mr3']//a[starts-with(@href, 'http')]/@href").get() if website: website = website.strip() phone = response.xpath("//li[@class='dib ml3 mr3'] //span[contains(text(), 'Phone:')]/following-sibling::text()").get() if phone: phone = phone.strip().replace("-","") yield{ 'title':title, 'address':address, 'website':website, 'phone':phone }
调优注意事项
- 如果运行时提示找不到加载更多按钮,直接打开浏览器开发者工具,在Elements面板搜索
load more找到对应按钮的属性,替换代码里的CSS选择器即可 click_wait参数建议不要小于1秒,避免请求过快被网站拦截- 该站点的展商详情页是静态渲染的,不需要走Selenium加载,直接用普通Scrapy Request爬取可以大幅提升效率,可根据需求调高Scrapy并发配置
- 若爬取过程中遇到验证码、访问拦截,可以在Selenium配置里添加随机UA、代理,适当拉长点击间隔
内容的提问来源于stack exchange,提问作者Amen Aziz
相关产品推荐
相关产品推荐

