You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

多线程+代理爬虫出现数据缺失问题求助(图片URL、颜色变体不全)

多线程+代理爬虫出现数据缺失问题求助(图片URL、颜色变体不全)

老哥,我看了你这段爬虫代码和遇到的问题,大概率是这几个地方出了问题,咱们一步步来捋:

一、代理稳定性与请求容错问题

你的问题里提到部分产品图片为空、颜色变体少,首先要怀疑代理的问题:

  • 代理请求失败/返回不完整内容:你用了proxy_waterfall.waterfall_hits获取页面,但代码里没对返回的variant_source做非空判断。如果某个代理请求失败返回空,直接执行html.fromstring(variant_source)会报错,后续逻辑直接跳过,这个颜色变体就没被抓取,自然少了一个;还有些代理可能被网站识别,返回的页面不完整(比如图片的XPath节点缺失),导致图片数为0。
  • 解决建议
    1. 给代理请求加非空判断和重试逻辑:
      variant_source = proxy_waterfall.waterfall_hits('GET', site_url, headers, '')
      # 增加非空判断,为空则重试或跳过
      if not variant_source:
          print(f"代理请求失败,跳过变体URL: {site_url}")
          # 可选:增加重试逻辑,比如重试2次
          for retry in range(2):
              variant_source = proxy_waterfall.waterfall_hits('GET', site_url, headers, '')
              if variant_source:
                  break
          else:
              continue  # 重试2次都失败,直接跳过
      variant_html = html.fromstring(variant_source)
      
    2. 检查代理池质量:统计代理请求的状态码,如果有大量403、500、404,说明代理被网站拉黑或质量差,需要更换代理池,或者给代理增加存活检测。

二、多线程的请求频率与反爬规避问题

你用了10个线程爬1000个URL,还每个URL要爬多个颜色变体,请求频率太高很容易触发网站反爬:

  • 网站限流/返回不完整内容:你现在的time.sleep(0.01)几乎等于无延迟,网站很容易识别出爬虫,返回截断的页面(比如少了一个颜色变体的节点,或者图片URL的节点),导致数据缺失。
  • 解决建议
    1. 增大请求间隔,用随机间隔避免被识别:
      import random
      # 把time.sleep(0.01)改成随机间隔
      time.sleep(random.uniform(0.8, 2.5))  # 随机0.8-2.5秒间隔
      
    2. 给请求增加超时时间:在proxy_waterfall.waterfall_hits的请求里设置timeout(比如10秒),避免请求挂起占用线程资源。
    3. 降低线程数试试?虽然你说降了没用,但可以降到5个再测试,排除线程数过多导致的请求拥堵。

三、页面解析逻辑的漏洞

有时候不是代理或线程的问题,是你解析页面的逻辑本身有问题:

  • 颜色变体的XPath不准确:你用variant_color_list = html_content.xpath(constants.VARIANT_COLOR_LIST_XPATH)去抓颜色变体,然后转集合去重,但可能这个XPath本身就没抓到所有变体。比如有些颜色是动态加载的,静态HTML里只有3个,剩下2个是滚动或点击后才加载的,lxml解析静态HTML自然抓不到。
  • 图片URL的解析逻辑有问题get_image_urls里的XPath可能只适配了部分产品,有些产品的图片是懒加载的,真实URL存在data-src而不是src属性里,你的XPath没取对,导致图片数为0。
  • 解决建议
    1. 手动验证XPath:打开那些爬不到的产品URL,用浏览器开发者工具的Console执行你的XPath,看看返回的结果数量是不是和页面显示的一致。比如颜色变体的XPath,执行后如果只返回4个,那就是XPath写错了,需要调整。
    2. 处理动态内容:如果是JS动态加载的内容,静态HTML抓不到,建议换成requests_html、Selenium或Playwright这类能渲染JS的工具,虽然速度慢,但能拿到完整的页面内容。

四、代码里的遗漏逻辑

看你的代码,还有两个明显的问题:

  1. 语法错误main函数里的wif concurrent.futures.ThreadPoolExecutor是笔误,应该是with,这个会导致代码报错,先修复这个。
  2. 数据存储逻辑缺失extract_data函数里循环处理完每个尺码的product_info后,没有调用MongoDB的插入方法(比如mongodb_utilities.insert_one(product_info)),如果没存的话,你根本拿不到数据;如果是在循环外面存,那最后只存了最后一个尺码的数据,也会导致数据缺失!
    • 修复建议:在for sz_info in size_info:循环内部,每次update完product_info就插入到MongoDB:
      for sz_info in size_info:
          # ... 你的update逻辑 ...
          product_info.update({...})
          # 新增:插入数据到MongoDB,用copy避免后续update覆盖已存数据
          mongodb_utilities.insert_one(product_info.copy())
      

最后总结排查步骤

  1. 先修复代码里的语法错误和数据存储逻辑,确保爬取到的数据能正确存入数据库。
  2. 给代理请求加非空判断和重试,排除代理失败导致的变体丢失。
  3. 增大请求间隔,降低反爬风险,看数据缺失是否改善。
  4. 手动验证XPath的正确性,确认解析逻辑没问题。
  5. 如果以上都没用,就换成渲染JS的工具爬,看看是不是动态内容导致的。

备注:内容来源于stack exchange,提问作者adhikari shehzeen

火山引擎 最新活动