scrapy部件
- ScrapyEngine:核心 负责工作。。。
- Scheduler:调度负责处理request请求
- Downloader:根据请求下载,得到respose
- Spider:分解response(下载下来的东西),得到数据和链接
- DownloaderMiddleware:下载中间件,自定义拓展功能(请求和反馈进行预处理),一个中间件完成一个功能
- SpiderMiddleware:拓展spider(请求和反馈进行预处理)
- ItemPipline:详细处理分析清洗数据(打包处理好数据)
scrapy文件及函数理解
- spiders.py:包含爬虫文件,以下是爬虫类中的方法和变量
- name ,它是每个项目唯一的名字,用来区分不同的 Spider,爬虫文件里可以有很多个类,如果我们要再写多一个spider, 可以用
#domain 域名
scrapy genspider [options] name domain
#不用手动配置相关的。。
- allowed_domains ,它是允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过虑掉
- 其中的parse函数用来处理response,提取数据,提交item,还能翻页
- start_urls,url列表
- custom settings 它是 个字典,是专属于本 Spider 的配置,此设置会覆盖项目全局的设
此设置必须在初始化前被更新,必须定义成类变量 - crawler:它是由 from_crawler()方法设置的,代表的是本Spider 类对应的Crawler 对象Crawer 对象包含了很多项目组件,利用它我们可以获取项目的 些配置信息,如最常见的获取项目的设置信息,即Settings
- settings: 它是 Settings对象,利用它我们可以直接获取项目的全局设置变量,除了基础属性,Spider还有些常用的方法
- start_requests(): 此方法用于生成初始请求,它必须返回一个可迭代对象 此方法会默认
使用 start_urls 里面的URL 来构造 Request ,而 Request是GET请求方式 如果我们想在启
动时以 POST 方式访问某个站点,可以直接重写这个方法,发送 POST 请求时使用 FormRequest即可 - closed() :Spider 关闭时,该方法会被调用
- middlewares.py:定义Spider Middlewares 和Downloader Middlewares的实现
- Downloader Middlewares:函数略
自定义的 Downloader Middleware 要添加到项目里, DOWNLOADER_MIDDLEWARES_BASE 变量不能直接修改,修改变量DOWNLOADER_MIDDLEWARES ,向其中添加自定义的 Downloade Middleware ,以及禁用 DOWNLOADER MIDDLEWARES BASE 的定义 - 修改请求时的user_agent:在settings里面添加user_agent或用process_request()方法
在settings.py中添加
MY_USER_AGENT = [可用的User-Agent]
在middlewares.py文件中添加
import scrapy
from scrapy import signals
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware
import random
class MyUserAgentMiddleware(UserAgentMiddleware): # 继承自UserAgentMiddleware
'''
设置User-Agent
'''
def __init__(self, user_agent):
self.user_agent = user_agent
@classmethod
def from_crawler(cls, crawler):
return cls(
user_agent=crawler.settings.get('MY_USER_AGENT') # 从settings里面取出USER_AGENT列表
)
def process_request(self, request, spider):
agent = random.choice(self.user_agent)
request.headers['User-Agent'] = agent
# 添加到headers里面,最后默认返回None
将自定义的MyUserAgentMiddleware类添加到DOWNLOADER_MIDDLEWARES
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,
'myproject.middlewares.MyUserAgentMiddleware': 400,
}
-
Spider Middlewares同上
-
- 定义item数据结构,就像一个字典,不过使用的时候要实例化
- 继承 scrapy.Item 类,并且定义类型为 scrapy.Field 字段
-
settings.py:定义项目的全局配置
-
以下是简单理解(其实我对它很好奇)
BOT_NAME = 'xiaozhu' 项目名称
SPIDER_MODULES = ['xiaozhu.spiders'] 爬虫文件路径
NEWSPIDER_MODULE = 'xiaozhu.spiders'
Crawl responsibly by identifying yourself (and your website) on the user-agent
设置模拟浏览器加载
USER_AGENT = 'qidianwang (+http://www.yourdomain.com)'
Obey robots.txt rules
是否遵守robot协议(默认为True表示遵守)
ROBOTSTXT_OBEY = False
Configure maximum concurrent requests performed by Scrapy (default: 16)
? scrapy 发起请求的最大并发数量(默认是16个)
CONCURRENT_REQUESTS = 32
Configure a delay for requests for the same website (default: 0)
See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
See also autothrottle settings and docs
设置下载延时,默认为0
DOWNLOAD_DELAY = 0
The download delay setting will honor only one of:
在每个域下允许发起请求的最大并发数(默认是8个)
CONCURRENT_REQUESTS_PER_DOMAIN = 16
针对每个ip允许发起请求的最大并发数量(默认0个)
1.在不为0的情况CONCURRENT_REQUESTS_PER_IP的设置优先级要比CONCURRENT_REQUESTS_PER_DOMAIN要高
2.不为0的情况下DOWNLOAD_DELAY就会针对于ip而不是网站了,
CONCURRENT_REQUESTS_PER_IP = 16
Disable cookies (enabled by default)
是否要携带cookies,默认为True表示携带
COOKIES_ENABLED = False
COOKIES_DEBUG 默认为False表示不追踪cookies
COOKIES_DEBUG = True
Disable Telnet Console (enabled by default)
====是一个扩展插件,通过TELENET可以监听到当前爬虫的一些状态,默认是True开启状态
TELNETCONSOLE_ENABLED = False
Override the default request headers:
=======请求头的设置
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8',
'Accept-Language': 'en',
'User-Agnet':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36',
}
Enable or disable spider middlewares
See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
爬虫中间件
SPIDER_MIDDLEWARES = {
'qidianwang.middlewares.QidianwangSpiderMiddleware': 543,
}
Enable or disable downloader middlewares
See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
下载中间件,自定义下载中间键需要在这里激活,后面的数字越小优先级越高,
DOWNLOADER_MIDDLEWARES = {
'qidianwang.middlewares.QidianUserAgentDownloadmiddlerware': 543,
'qidianwang.middlewares.QidianProxyDownloadMiddlerware':544,**
'qidianwang.middlewares.SeleniumDownlaodMiddlerware':543,
}
Enable or disable extensions
See https://doc.scrapy.org/en/latest/topics/extensions.html
EXTENSIONS================添加扩展
EXTENSIONS = {
'scrapy.extensions.telnet.TelnetConsole': None,
}
Configure item pipelines
See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
激活管道,后面跟的数字越小优先级越高
ITEM_PIPELINES = {
'qidianwang.pipelines.QidianwangPipeline': 300,
'scrapy_redis.pipelines.RedisPipeline': 400,
}
动态下载延时,(自动限速的扩展,默认情况下是关闭的)
使用步骤1.打开:AUTOTHROTTLE_ENABLED = True
Enable and configure the AutoThrottle extension (disabled by default)
See https://doc.scrapy.org/en/latest/topics/autothrottle.html
AUTOTHROTTLE_ENABLED = True
The initial download delay
初始的下载延时
AUTOTHROTTLE_START_DELAY = 5
The maximum download delay to be set in case of high latencies
最大的下载延时
AUTOTHROTTLE_MAX_DELAY = 60
The average number of requests Scrapy should be sending in parallel to
each remote server
发送到每一个服务器的并行请求数量
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
Enable showing throttling stats for every response received:
是否要开启自动限速的DEBUG模式
AUTOTHROTTLE_DEBUG = False
Enable and configure HTTP caching (disabled by default)
See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
=====数据缓存的一个扩展(默认情况下是关闭的为HTTPCACHE_ENABLED = False)
HTTPCACHE_ENABLED = True
=====设置缓存超时的时间
HTTPCACHE_EXPIRATION_SECS = 0
=====设置缓存保存的路径
HTTPCACHE_DIR = 'httpcache'
=====缓存忽略的响应状态码设置为400表示忽略掉不缓存 : HTTPCACHE_IGNORE_HTTP_CODES = ['400']
HTTPCACHE_IGNORE_HTTP_CODES = []
缓存的储存插件,
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
将log日志信息保存在本地文件
LOG_FILE = 'qdlogfile.log'
LOG_LEVEL = 'DEBUG'
- pipelines.py:定制与激活Itempipeline,对数据进行处理(比如限制或增删),进而存储数据(mongodb,mysql)
- process_item():
Item Pipeline 会自动调用这个方法,该方法必须返回包含数据的字典或 Item对象,或者抛出 Dropltem 异常
参数: 一个是 item ,每次 Spider 生成的 Item 都被传递
另一个是 spider ,就是spider 实例 - open_spider 当spider 开启时,这个方法被调用
- close_spider 当spider关闭时,这个方法会调用
- from_crawler 它是一个类方法,用@class method 标识, 是一种依赖注入的方式 它的参数就是 crawler ,通过 crawler 我们可以拿到全局配置的每个配置信息 在全局配置 settngs.py中,我们可以定义 MONGO_URI MONGO_DB 来指定 MongoDB 接需要的地址和数据库名称。拿到配置信息之后返回 对象即可 所以这个方法的定义主要是用来获取 settings.py 中的配置的
如
def __init__(self,mongo_url,mongo_db):
self.mongo_url = mongo_url
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return els(
mongo_uri=crawler.settings.get('MοNGO_URI ’),
mongo_db=crawler.settings.get(’ MONGO_DB')
)
- scrapy.cfg:配置scrapy项目文件路径,部署相关信息
学习与理解:selector与scrapy shell与xpath与css与正则
-
选择器:选择元素的一种方式,不同的选择其实用不同的方法
-
selector:可以脱离scrapy单独使用,一个强大的网页解析库
body= '<html><head><title>Hello World</title></head><body></body></ html> ’ selector = Selector(text=body)
生成了一个Selector 选择器对象 -
xpath:response .xpath () 是scrapy中对response.selector.xpath ()方法设置的快捷方式,得到Selectorlist 类型的变量, 由 Selector 对象组成的列表
-
xpath非常好用,跟正则搭配很完美
selenium
对于异步加载,一方面可以分析ajax找到对应的接口抓取,也可以用selenium或splash模拟浏览器
代码案例(对代码还没有完全理解)
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from scrapy.http import HtmlResponse
from logging import getLogger
class SeleniumMiddleware(object):
def __init__(self, timeout=None, service_args=[]):
self.logger = getLogger(__name__)
self.timeout = timeout # 设置页面超时时间
self.browser = webdriver.PhantomJS(service_args=service_args)
self.browser.set_window_size(1400, 700) # 设置页面大小
self.browser.set_page_load_timeout(self.timeout)
self.wait = WebDriverWait(self.browser, self.timeout)
def __del__(self):
self.browser.close()
def process_request(self, request, spider):
"""
用PhantomJS抓取页面
:param request: Request对象
:param spider: Spider对象
:return: HtmlResponse
"""
self.logger.debug('PhantomJS is Starting')
page = request.meta.get('page', 1)
try: # 调用 PhantomJS 对象的 get ()方法访问 Request 的对应的 URL ,相当于
Request 对象里获取请求链接,然后再用 PhantomJS 加载,不再使用 Scrapy 里的 Downloader
self.browser.get(request.url)
if page > 1:
input = self.wait.until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#mainsrp-pager div.form > input')))
submit = self.wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, '#mainsrp-pager div.form > span.btn.J_Submit')))
input.clear()
input.send_keys(page)
submit.click()
self.wait.until(
EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#mainsrp-pager li.item.active > span'), str(page)))
self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.m-itemlist .items .item')))
return HtmlResponse(url=request.url, body=self.browser.page_source, request=request, encoding='utf-8',
status=200)
except TimeoutException:
return HtmlResponse(url=request.url, status=500, request=request)
@classmethod
def from_crawler(cls, crawler):
return cls(timeout=crawler.settings.get('SELENIUM_TIMEOUT'),
service_args=crawler.settings.get('PHANTOMJS_SERVICE_ARGS'))
settings.py里设置
DOWNLOADER_MIDDLEWARES = {
"scrapyseleniumtest.middlewares.SeleniumMiddleware": 543,
}
Mongodb储存
Item Pipeline里
import pymongo
class MongoPipeline(object):
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(mongo_uri=crawler.settings.get('MONGO_URI'), mongo_db=crawler.settings.get('MONGO_DB'))
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def process_item(self, item, spider):
self.db[item.collection].insert(dict(item))
return item
def close_spider(self, spider):
self.client.close()
settings.py 添加
# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = { # 开启这个类的调用
'scrapyseleniumtest.pipelines.MongoPipeline': 300,
}
MONGO_URI = 'localhost'
MONGO_DB = 'taobao'
#注明这两个
分布式爬虫
-
单爬虫
-
单机限制于网络速度
-
IO吞吐量 网线限制
-
多爬虫问题
-
数据共享:同步
-
自动分工机制,充分利用资源提高效率
-
Redis功能(内存数据库,同时保存到硬盘):
-
安装(略)
-
内容保存数据库:Mongdb,Mysql等(运行在内存,数据保存在硬盘?,控制保存时间)
-
简单原理理解
-
由Redis管理请求队列(排重保存),scrapy自己的请求队列就不再使用(在settings里面设置队列为远程)
学习推荐(成为爬虫专家必读)
- Python爬虫开发与项目实战(范传辉,机械工业)
- 精通Python爬虫框架scrapy(李斌译,人民邮电)
- 崔庆才
内存数据库的简单理解
- 目的:充分利用CPU的周期和内存(充分利用内存技术提升数据库性能)
- 几乎将整个数据库放进内存中,是对数据库管理系统的重新设计(重新设计和优化了算法与数据结构)
- https://blog.csdn.net/DH2442897094/article/details/64440130