为何Scrapy选择器仅获取父元素?Trezor页面爬取问题咨询
解决Scrapy选择器爬取Trezor币种页面只返回空tr标签的问题
我来帮你搞定这个爬取问题!先还原下你遇到的场景:
问题重现
你用requests获取Trezor币种页面的原始HTML,再用Scrapy选择器提取表格行时,只拿到了空的<tr>标签,代码和结果如下:
import requests from scrapy.selector import Selector req = requests.get('https://trezor.io/coins/').content xs = '//*[@id="content"]/tr' sel = Selector(text=req).xpath(xs) print(sel.extract_first()) # 输出: '<tr class="coin " data-href="./#BTC" id="BTC"></tr>'
而爬维基百科静态页面时却能正常获取到完整元素内容,这确实让人摸不着头脑。
问题根源
核心原因是Trezor的币种表格是动态加载的:
- 服务器返回的原始HTML里,只有空的
<tr>框架,里面的<td>内容是页面加载完成后,通过JavaScript从后端接口拉取数据并渲染出来的。 requests.get只能拿到服务器返回的初始静态HTML,不会执行页面的JavaScript,所以看不到渲染后的<td>元素。- 维基百科的内容是直接嵌入在静态HTML里的,所以能直接爬取到完整内容。
解决方案
有两种高效的解决方法,你可以根据需求选择:
方法1:用Scrapy集成JS渲染工具(推荐)
可以使用scrapy-playwright让Scrapy模拟浏览器渲染页面,等待JS执行完成后再爬取内容。
- 先安装依赖:
pip install scrapy-playwright playwright install chromium
- 在Scrapy项目的
settings.py里配置:
DOWNLOAD_HANDLERS = { "http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler", "https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler", } PLAYWRIGHT_LAUNCH_OPTIONS = { "headless": True, # 无头模式,不显示浏览器窗口 "timeout": 30000, }
- 编写爬虫代码:
import scrapy from scrapy_playwright.page import PageCoroutine class TrezorCoinsSpider(scrapy.Spider): name = "trezor_coins" start_urls = ["https://trezor.io/coins/"] def start_requests(self): for url in self.start_urls: yield scrapy.Request( url, meta={ "playwright": True, # 等待表格内容加载完成 "playwright_page_coroutines": [ PageCoroutine("wait_for_selector", "tr.coin td"), ], }, ) def parse(self, response): # 现在可以正常提取所有<tr>里的<td>内容了 for row in response.xpath('//*[@id="content"]/tr[not(@class="header")]'): yield { 'coin_id': row.xpath('./@id').get(), 'full_name': row.xpath('./td[1]/text()').get().strip(), 'symbol': row.xpath('./td[2]/text()').get().strip(), 'type': row.xpath('./td[3]/text()').get().strip(), 'support_status': row.xpath('./td[4]/text()').get().strip(), 'segwit_support': row.xpath('./td[5]/text()').get().strip(), 'notes': row.xpath('./td[6]/text()').get().strip() if row.xpath('./td[6]/text()').get() else '' }
方法2:直接爬取后端API(更高效)
打开浏览器开发者工具的「Network」标签,刷新页面后可以找到加载币种数据的API接口,直接请求这个接口获取JSON格式的数据,比爬页面更简单高效:
import requests # 通过浏览器开发者工具找到加载币种数据的API接口地址 api_url = "你找到的API接口地址" response = requests.get(api_url) coins_data = response.json() # 遍历提取数据 for coin in coins_data: print(f"币种名称: {coin['name']}, 符号: {coin['symbol']}, 支持状态: {coin['support']}")
这样就能轻松获取到所有币种的完整数据啦!
内容的提问来源于stack exchange,提问作者manoelpqueiroz
相关产品推荐
相关产品推荐

