为何Scrapy无法抓取该网页?附爬虫代码及执行异常信息
我来帮你排查这个Scrapy爬虫的问题,先梳理下你的情况:
你要抓取的目标页面是:http://www.oddsportal.com/search/results/:69Dxbc61/,编写的Scrapy代码如下:
import scrapy class Test2Spider(scrapy.Spider): name = "test2" allowed_domains = ["oddportal.com"] start_urls = ( 'http://www.oddsportal.com/search/results/:69Dxbc61/', ) def parse(self, response): for partita in response.css('tr.deactivate'): yield { 'score': partita.css('td.table-score::text').extract_first(), }
执行命令:
scrapy runspider test2.py -o uno.json
之后出现了异常(你提供的异常内容截断为:2018-04-19 16:45:56 [scr...)
结合代码和目标网站的特性,大概率是以下几个问题导致的,我逐一给你拆解:
1. 域名拼写错误(最可能的直接原因)
你代码里的allowed_domains写的是"oddportal.com",但目标网站的正确域名是oddsportal.com(多了一个s)!这个小错误会让Scrapy直接过滤掉对目标网站的请求,要么返回空结果,要么抛出域名不被允许的异常。
修复方法:把allowed_domains修改为正确的域名:
allowed_domains = ["oddsportal.com"]
2. 动态页面渲染问题
Oddsportal的很多内容是通过JavaScript动态加载的,而Scrapy默认只能抓取静态HTML源码。如果你要找的tr.deactivate元素是JS动态生成的,直接用CSS选择器肯定抓不到任何内容。
解决思路:
- 方案一:用Scrapy Splash渲染动态页面:需要先安装Splash服务和
scrapy-splash库,让爬虫模拟浏览器加载JS内容。 - 方案二:直接请求AJAX接口:打开浏览器开发者工具的「网络」面板,找到加载赛事数据的AJAX接口,直接请求这个接口获取结构化数据,这种方式效率更高,也更稳定。
3. 反爬机制拦截
Oddsportal有反爬策略,比如检查请求的User-Agent、IP访问频率等。Scrapy默认的User-Agent很容易被识别,导致请求被拒绝或者返回空白页面。
修复方法:在Scrapy的settings.py文件中添加自定义的User-Agent:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
如果还是被拦截,可以进一步添加IP代理、设置请求延迟(DOWNLOAD_DELAY = 2)等反反爬措施。
4. CSS选择器准确性问题
即使页面是静态的,也要确认你的CSS选择器是否能匹配到目标元素。你可以在浏览器的开发者工具控制台中输入document.querySelectorAll('tr.deactivate'),看看是否能返回预期的元素。如果没有结果,说明选择器需要调整,比如可能是tr.active或者其他类名。
修改完域名后,先在parse方法里打印响应内容的开头部分,确认是否正常获取到了页面:
def parse(self, response): # 打印响应前500个字符,检查页面是否正常返回 print(response.body[:500]) for partita in response.css('tr.deactivate'): yield { 'score': partita.css('td.table-score::text').extract_first(), }
如果打印的内容和浏览器看到的页面源码一致,再排查选择器或动态加载的问题;如果内容是空白或有反爬提示,就需要处理反爬策略了。
内容的提问来源于stack exchange,提问作者xRobot

