Python中使用scrapy+splash爬取leetcode的问题
新手刚开始学习爬虫不久,现在正在尝试使用 splash 来爬取用 js 渲染的动态页面,比如从 https://leetcode.com/problemset/all/ 爬取各种题目信息。
但是在 https://leetcode.com/problems/two-sum/ 这种页面中调用 response.xpath("//div[@class=‘css-1ponsav’]")似乎并不能获取到任何信息,不知道是什么原因?
同理在 https://leetcode.com/accounts/login/ 登陆界面里试图调用 SplashFormRequest.from_response(response,…)来进行登陆操作的时候也会返回 ValueError: No <form> element found in <200 https://leetcode.com/accounts/login/>,似乎并没有抓取到表格信息?
本人不太了解前端,不知道这个跟 leetcode 用的 graphQL 有没有关系?还是因为其它原因?
Python中使用scrapy+splash爬取leetcode的问题
为啥不直接用 graphql 接口?
我最近也在用Scrapy+Splash爬LeetCode,分享一个完整的代码示例。
首先确保环境:pip install scrapy scrapy-splash,然后启动Splash服务(Docker运行:docker run -p 8050:8050 scrapinghub/splash)。
核心代码:
import scrapy
from scrapy_splash import SplashRequest
class LeetcodeSpider(scrapy.Spider):
name = 'leetcode'
start_urls = ['https://leetcode.com/problemset/all/']
def start_requests(self):
for url in self.start_urls:
yield SplashRequest(
url,
self.parse,
args={'wait': 2, 'timeout': 90}
)
def parse(self, response):
# 等待表格加载
script = """
function main(splash)
splash:go(splash.args.url)
splash:wait(2)
return splash:html()
end
"""
yield SplashRequest(
response.url,
self.parse_table,
endpoint='execute',
args={'lua_source': script, 'timeout': 90},
dont_filter=True
)
def parse_table(self, response):
# 提取题目信息
for row in response.css('div[role="row"]'):
title = row.css('a[href*="/problems/"]::text').get()
difficulty = row.css('span.difficulty-label::text').get()
acceptance = row.css('span.text-label::text').get()
if title:
yield {
'title': title.strip(),
'difficulty': difficulty.strip() if difficulty else None,
'acceptance': acceptance.strip() if acceptance else None,
'url': response.urljoin(row.css('a[href*="/problems/"]::attr(href)').get())
}
# 处理分页
next_page = response.css('a[aria-label="next"]::attr(href)').get()
if next_page:
yield SplashRequest(
response.urljoin(next_page),
self.parse_table,
args={'wait': 2}
)
settings.py配置:
SPLASH_URL = 'http://localhost:8050'
DOWNLOADER_MIDDLEWARES = {
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
运行:scrapy crawl leetcode -o leetcode.json
关键点:
- 用SplashRequest替代普通Request
- 适当设置wait时间让JS加载
- LeetCode的DOM结构可能变化,需要根据实际情况调整选择器
- 注意频率控制,避免被封
总结:用Splash处理LeetCode的JS渲染很有效。
会不会没有渲染完你就去获取了?给个延时试试?
用接口解决了问题。。。

