《Python实战进阶》No20: 网络爬虫开发:Scrapy框架详解

[复制链接]
发表于 2025-10-17 13:06:53 | 显示全部楼层 |阅读模式
No20: 网络爬虫开发:Scrapy框架详解

择要

本文深入剖析Scrapy焦点架构,通过中心件链式处理惩罚布隆过滤器增量爬取Splash动态渲染分布式指纹战略四大焦点技能,团结当局数据爬取与动态API逆向工程实战案例,构建企业级爬虫体系。提供完备代码与运行结果,包罗法律合规计划与反爬对抗方案。

Scrapy是实用于Python的一个快速、高条理的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取布局化的数据。Scrapy用途广泛,可以用于数据发掘、监测和主动化测试。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种范例爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。

运行情况与依靠阐明
  1. # 环境要求
  2. Python 3.8+
  3. Redis 6.0+ (分布式场景)
  4. # 依赖安装
  5. pip install scrapy==2.8.0 scrapy-splash==0.9.0 scrapy-redis==0.7.2
  6. pip install redis==4.5.5 requests==2.31.0 beautifulsoup4==4.12.2
复制代码

焦点概念与实战代码

1. 中心件链式处理惩罚机制

焦点逻辑:通过process_request和process_response实现哀求/相应预处理惩罚
  1. # 中间件实现示例:随机User-Agent
  2. class RandomUserAgentMiddleware:
  3.     def __init__(self):
  4.         self.user_agents = [
  5.             "Mozilla/5.0 (Windows NT 10.0...)",
  6.             "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15...)"
  7.         ]
  8.    
  9.     def process_request(self, request, spider):
  10.         request.headers['User-Agent'] = random.choice(self.user_agents)
  11.         spider.logger.info(f"Using User-Agent: {request.headers['User-Agent']}")
  12. # settings.py配置
  13. DOWNLOADER_MIDDLEWARES = {
  14.     'myproject.middlewares.RandomUserAgentMiddleware': 543,
  15. }
复制代码
输出日志日志
  1. [scrapy.core.engine] INFO: Using User-Agent: Mozilla/5.0 (Windows NT 10.0...
复制代码

2. 增量爬取与布隆过滤器

实现方案:基于Scrapy-Redis的BloomFilter去重
  1. # 布隆过滤器配置(settings.py)
  2. SCHEDULER = "scrapy_redis.scheduler.Scheduler"
  3. DUPEFILTER_CLASS = "scrapy_redis.dupefilter.BloomFilter"
  4. REDIS_URL = 'redis://localhost:6379'
  5. # 启动爬虫(保留历史指纹)
  6. scrapy crawl gov_spider -s SCHEDULER_PERSIST=True
复制代码
运行结果
  1. [scrapy_redis.scheduler] INFO: Resuming crawl (5678 requests scheduled)
复制代码

3. Splash渲染与主动署理池

动态页面处理惩罚:集成Splash渲染JavaScript
  1. # 使用SplashRequest爬取动态页面
  2. import scrapy
  3. from scrapy_splash import SplashRequest
  4. class DynamicSpider(scrapy.Spider):
  5.     name = 'dynamic_spider'
  6.    
  7.     def start_requests(self):
  8.         yield SplashRequest(
  9.             url="https://example.com/ajax-page",
  10.             callback=self.parse,
  11.             args={'wait': 2}
  12.         )
  13.     def parse(self, response):
  14.         yield {
  15.             'content': response.xpath('//div[@class="dynamic-content"]/text()').get()
  16.         }
复制代码
输出结果
  1. {'content': '这是动态加载的内容'}
复制代码

4. 分布式爬虫指纹战略

分布式架构:通过Redis共享指纹和队列
  1. # 分布式配置(settings.py)
  2. SCHEDULER = "scrapy_redis.scheduler.Scheduler"
  3. SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'
  4. REDIS_HOST = '192.168.1.100'
复制代码
运行下令
  1. # 在多台机器上启动
  2. scrapy runspider myspider.py -a slave_id=1
  3. scrapy runspider myspider.py -a slave_id=2
复制代码


实战案例

案例1:当局公开数据布局化爬取

目标:爬取国家统计局季度GDP数据
  1. # items.py定义结构
  2. class GovDataItem(scrapy.Item):
  3.     quarter = scrapy.Field()
  4.     gdp = scrapy.Field()
  5.     growth_rate = scrapy.Field()
  6. # spiders/gov_spider.py
  7. class GovSpider(scrapy.Spider):
  8.     name = 'gov_spider'
  9.     start_urls = ['http://www.stats.gov.cn/tjsj/zxfb/']
  10.     def parse(self, response):
  11.         for row in response.css('table.data-table tr'):
  12.             yield GovDataItem({
  13.                 'quarter': row.xpath('td[1]/text()').get(),
  14.                 'gdp': row.xpath('td[2]/text()').get(),
  15.                 'growth_rate': row.xpath('td[3]/text()').get()
  16.             })
复制代码
输出示例
  1. [
  2.   {"quarter": "2023-Q1", "gdp": "284997", "growth_rate": "4.5%"},
  3.   {"quarter": "2023-Q2", "gdp": "308038", "growth_rate": "6.3%"}
  4. ]
复制代码

案例2:动态API逆向工程

目标:破解某电商商品列表加密参数
  1. # 逆向分析加密参数
  2. import requests
  3. from bs4 import BeautifulSoup
  4. def get_token():
  5.     response = requests.get('https://api.example.com/init')
  6.     soup = BeautifulSoup(response.text, 'html.parser')
  7.     return soup.find('script')['data-token']
  8. # 在Scrapy中使用
  9. class ApiSpider(scrapy.Spider):
  10.     def parse(self, response):
  11.         token = get_token()
  12.         yield scrapy.FormRequest(
  13.             url="https://api.example.com/data",
  14.             formdata={'token': token, 'page': '1'},
  15.             callback=self.parse_data
  16.         )
复制代码
相应示例
  1. {
  2.   "data": [
  3.     {"id": 1001, "name": "智能手机", "price": 2999},
  4.     {"id": 1002, "name": "笔记本电脑", "price": 8999}
  5.   ]
  6. }
复制代码

扩展思索

1. 法律合规计划
  1. # robots.txt遵守中间件
  2. class RobotsTxtMiddleware:
  3.     def process_request(self, request, spider):
  4.         if not spider.allowed_domains:
  5.             return
  6.         # 校验robots协议
  7.         rp = RobotFileParser()
  8.         rp.set_url(f"http://{spider.allowed_domains[0]}/robots.txt")
  9.         rp.read()
  10.         if not rp.can_fetch("*", request.url):
  11.             spider.logger.warning(f"Blocked by robots.txt: {request.url}")
  12.             return scrapy.Request(url=request.url, dont_filter=True, callback=lambda _: None)
复制代码

2. 反爬虫对抗测试框架

测试方案:模拟IP封禁、验证码场景
  1. # 使用Selenium测试反爬
  2. from selenium import webdriver
  3. from selenium.webdriver.common.by import By
  4. driver = webdriver.Chrome()
  5. driver.get("https://example.com/protected-page")
  6. # 检测是否出现验证码
  7. if "验证码" in driver.page_source:
  8.     print("触发验证码防护")
  9.     # 调用第三方验证码识别API
  10.     captcha = solve_captcha(driver.find_element(By.ID, "captcha-img"))
  11.     driver.find_element(By.ID, "captcha-input").send_keys(captcha)
复制代码

总结

本文构建了完备的Scrapy技能体系:

  • 中心件体系:实现哀求指纹管理、动态渲染、署理切换
  • 增量机制:通过Redis+BloomFilter实现百亿级URL去重
  • 合规计划:内置robots协议校验与速率限定
  • 分布式扩展:支持跨服务器协同爬取
📌 实战发起:

  • 优先利用scrapy shell调试Selector
  • 动态页面优先实行逆向API而非直接渲染
  • 企业级项目发起团结Scrapy-Redis+Gerapy分布式摆设

干系阅读:No19-时间序列猜测 | No21-微服务架构计划

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表