You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy跳转整个HTML元素而非链接的问题排查与解决

问题分析与解决

核心错误点

  • 链接提取错误:你用link.get()获取的是整个<a>标签的HTML代码,而非链接地址,导致Scrapy把整个标签拼接到基础URL后,产生无效的404链接。
  • 回调函数错误:parse里调用response.follow时指定了callback=self.parse,会重复调用列表页解析函数,应该指向处理详情页的parse_links。
  • 动态渲染处理缺失:目标网站的链接是通过Knockout.js动态绑定的,静态HTML中a标签没有实际的href属性,需要从data-bind属性里提取目标URL。
  • 详情页选择器无效:parse_links里的CSS选择器为空,且td.[email_address]是错误写法,无法定位邮箱元素。

修正后的代码

import scrapy
import re

class ContractorSpider(scrapy.Spider):
    name = "contractor"
    start_urls = ['https://lslbc.louisiana.gov/contractor-search/search-type-contractor/']

    def parse(self, response):
        # 从a标签的data-bind属性中提取showURL相关内容
        links = response.xpath('//*[@id="search-results"]/table/tbody/tr/td/a/@data-bind')
        for link in links:
            data_bind_content = link.get()
            # 用正则匹配出showURL对应的路径值
            url_pattern = re.search(r"'(.*?)'", data_bind_content)
            if url_pattern:
                contractor_path = url_pattern.group(1)
                # 拼接完整的详情页URL
                full_url = f"https://lslbc.louisiana.gov{contractor_path}"
                yield scrapy.Request(full_url, callback=self.parse_links)

    def parse_links(self, response):
        # 根据页面实际结构调整选择器,这里假设邮箱在class为email_address的td中
        contractor_name = response.css('h2.company-title::text').get()
        contractor_email = response.css('td.email_address::text').get()
        
        if contractor_name and contractor_email:
            yield {
                'name': contractor_name.strip(),
                'email': contractor_email.strip()
            }

高效优化建议

目标网站的承包商数据是通过AJAX接口动态加载的,直接解析静态HTML容易受前端渲染逻辑影响。更可靠的方式是:

  1. 打开浏览器开发者工具的Network面板,过滤XHR请求;
  2. 找到admin-ajax.php的请求,复制其URL、请求参数和Headers;
  3. 直接编写请求调用该接口,获取JSON格式的完整承包商数据,无需解析页面链接,效率更高且更稳定。

内容的提问来源于stack exchange,提问作者anon_0122

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:48:19