Scrapy的启动和debug
命令行
scrapy crawl jd_search
启动脚本
# 新建run.py from scrapy import cmdline command = "scrapy crawl jd_search".split() cmdline.execute(command)
Scrapy Item
只是对解析的结构化结果进行一个约束, 在到达pipeline前就可以检查出数据错误.
Scrapy的设置
*ROBOTTEXT_OBEY
ROBOTTEXT_OBEY=False
获取对方网站是否允许爬虫获取数据的信息.
设置中间件
数字越小, 离
ENGINE
越近DOWNLOADER_MIDDLEWARES = { # 'jd_crawler_scrapy.middlewares.JdCrawlerScrapyDownloaderMiddleware': 543, 'jd_crawler_scrapy.middlewares.UAMiddleware': 100, }
设置PIPELINE
ITEM_PIPELINES = { 'jd_crawler_scrapy.pipelines.JdCrawlerScrapyPipeline': 300, }
请求限制
*CONCURRENT_REQUESTS
请求并发数, 通过控制请求并发数达到避免或者延缓IP被封禁
CONCURRENT_REQUESTS = 1
CONCURRENT_REQUESTS_PER_DOMAIN
控制每个
域名
请求的并发数CONCURRENT_REQUESTS_IP
控制每个
IP
请求的次数. 通过这样的方式可以过掉一些对IP封禁严格的网站.CONCURRENT_ITEMS
默认为100, 控制处理
item
的并发数. 如果我存入的数据库性能比较差, 通过这样的方式解决防止数据库崩溃的情况.*DOWNLOAD_DELAY
默认为0, 控制请求的频率. 在调度完一个请求后, 休息若干秒.
Scrapy会自动帮我们进行随机休息 (DOWNLOAD_DELAY - 0.5, DOWNLOAD_DELAY + 0.5)
DOWNLOAD_DELAY = 2
*DOWNLOAD_TIMEOUT
控制每个请求的超时时间. 通过这样的方式解决IP代理池质量差的问题.
# 根据自己的IP代理池质量自定决定 DOWNLOAD_TIMEOUT = 6
*REDIRECT_ENABLE
默认为
True
, 建议修改为False
, 因为大部分情况下, 重定向都是识别出你当前身份有问题, 重定向到log in
页面
重试机制
*RETRY_ENABLE
RETYR_ENABLE = False
默认为
True
, 建议改成False
, 然后自己重写重试中间件RETRY_TIMES
控制重新次数, RETRY_TIMES其实是当前项目的兜底配置
如果当前请求失败后永远会重试, 正好你请求的接口是收费的, 万一有一天报错, 那么产生的费用是巨大的.
RETRY_TIMES = 3
RETRY_HTTP_CODES
RETRY_HTTP_CODES = [500, 502, 503, 504, 408, 429]
过滤器
设置中指定过滤器
DUPEFILTER_CLASS = "jd_crawler_scrapy.middlewares.MyRFPDupeFilter"
Spider中打开过滤器
yield scrapy.FormRequest( dont_filter=False, url=url, method='GET', # formdata=data, callback=self.parse_search )
过滤器
from scrapy.dupefilters import RFPDupeFilter from w3lib.url import canonicalize_url from scrapy.utils.python import to_bytes import hashlib import weakref class MyRFPDupeFilter(RFPDupeFilter): """ 过滤器是在到达下载器之前就生成了过滤指纹, 如果我们的下载器中间件报错了, 那么过滤指纹仍然生效, 但是没有实际请求. 所以我们可以通过一些特殊参数来进行自定义过滤规则 """ def request_fingerprint(self, request, include_headers=None, keep_fragments=False): cache = _fingerprint_cache.setdefault(request, {}) cache_key = (include_headers, keep_fragments) if cache_key not in cache: fp = hashlib.sha1() fp.update(to_bytes(request.method)) fp.update(to_bytes(canonicalize_url(request.url, keep_fragments=keep_fragments))) fp.update(request.body or b'') fp.update(request.meta.get("batch_no", "").encode("utf-8")) cache[cache_key] = fp.hexdigest() return cache[cache_key]
LOG
LOG_ENABLE
默认为
True
, 是否使用logLOG_FILE
设置保存的log文件目录
LOG_LEVEL(按严重程序排序)
- CRITICAL
- ERROR
- WARNING
- INFO
- DEBUG
Scrapy的中间件
请求头中间件
class UAMiddleware: def process_request(self, request, spider): request.headers["user-agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"
重试中间件
from scrapy.downloadermiddlewares.retry import RetryMiddleware from scrapy.utils.response import response_status_message class MyRetryMiddleware(RetryMiddleware): """ 解决对方服务器返回正常状态码200, 但是根据IP需要进行验证码验证的情况. 我们可以通过换IP可以解决验证码, 那么就应该重试. """ def process_response(self, request, response, spider): if request.meta.get('dont_retry', False): return response if "验证码" in response.text: reason = response_status_message(response.status) return self._retry(request, reason, spider) or response return response
Comment here is closed