Python Scrapy爬取Wanikani汉字数据时txt文件为空问题排查
故障原因
你的爬虫拿不到数据是几个代码错误叠加导致的:
- XPath路径完全写错:你从浏览器复制的绝对路径带了错误的
/body/层级,Scrapy的响应DOM中body节点是html标签的直接子节点,不存在于id="main"的节点内部,所有XPath查询返回空列表,自然没有可写入的数据。同时你在遍历reading节点的循环里又写了全文档绝对路径,就算路径正确也会重复抓取全页数据。 - 文件操作逻辑错误:你写的
self.file.close只是引用了关闭方法,没有加括号执行,而且每写一条数据就尝试关闭文件,后续写入会直接失败;另外在类属性定义阶段就打开文件句柄,不符合Scrapy的生命周期,缓冲区的数据不会自动刷入磁盘,就算写入成功也会丢数据。 - 反爬拦截:Scrapy默认请求头的User-Agent带Scrapy标识,WaniKani会直接拦截这类请求,返回的页面根本没有你要找的汉字内容;默认开启的robots协议遵守规则也会直接拦截这类爬取请求。
- 无效代码:你写的
x.strip()没有接收返回值,Python字符串是不可变类型,不赋值的话strip操作完全不生效,空白字符不会被清理。
修复步骤
- 先修改Scrapy项目的
settings.py配置:- 把
ROBOTSTXT_OBEY = True改成ROBOTSTXT_OBEY = False - 替换默认USER_AGENT为普通浏览器标识,比如:
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
- 把
- 替换原爬虫代码为修正后的版本,主要修正了XPath定位、文件生命周期管理、数据清洗逻辑:
import scrapy class WanikaniSpider(scrapy.Spider): name = 'japandict' allowed_domains = ['www.wanikani.com'] base_url = 'https://www.wanikani.com/kanji/' kanjis = ['悪' ,'安' ,'以' ,'飲' ,'意' ,'医' ,'員' ,'運' ,'映' ,'英' ,'屋' ,'駅' ,'歌' ,'牛'] start_urls = [base_url + kanji for kanji in kanjis] def open_spider(self, spider): # 爬虫启动时统一打开四个文件 self.kanji_f = open("kanji.txt", "a", encoding="utf-8") self.onyomi_f = open("onyomi.txt", "a", encoding="utf-8") self.kunyomi_f = open("kunyomi.txt", "a", encoding="utf-8") self.meanings_f = open("meanings.txt", "a", encoding="utf-8") def close_spider(self, spider): # 爬虫结束时统一关闭文件,强制刷入缓冲区数据 self.kanji_f.close() self.onyomi_f.close() self.kunyomi_f.close() self.meanings_f.close() def parse(self, response): # 用class属性定位元素,避免写死层级导致路径失效 kanji_char = response.xpath('//h1[contains(@class, "kanji-icon")]/span[@lang="ja"]/text()').get('').strip() raw_meanings = response.xpath('//h1[contains(@class, "kanji-icon")]/text()').getall() meaning = ''.join([m.strip() for m in raw_meanings if m.strip()]) raw_onyomi = response.xpath('//div[contains(@class, "reading-section--onyomi")]//p/text()').getall() onyomi_list = [r.strip() for r in raw_onyomi if r.strip()] raw_kunyomi = response.xpath('//div[contains(@class, "reading-section--kunyomi")]//p/text()').getall() kunyomi_list = [r.strip() for r in raw_kunyomi if r.strip()] # 写入数据,中途不关闭文件 if kanji_char: self.kanji_f.write(kanji_char + "\n") for onyomi in onyomi_list: self.onyomi_f.write(onyomi + "\n") for kunyomi in kunyomi_list: self.kunyomi_f.write(kunyomi + "\n") if meaning: self.meanings_f.write(meaning + "\n")
额外说明
不要直接复制浏览器调试工具生成的一长串绝对XPath路径,这类路径靠div序号定位,页面结构稍微变动就会失效,尽量用元素的id、class等稳定属性做定位,鲁棒性更强。
内容的提问来源于stack exchange,提问作者Lawlace
相关产品推荐
相关产品推荐

