scrapy提供一个工具来生成项目,生成的项目中预置了一些文件,用户须要在这些文件中添加本身的代码。 打开命令行,执行:scrapy startproject tutorial,生成的项目相似下面的结构linux
tutorial/ scrapy.cfg tutorial/ __init__.py items.py pipelines.py settings.py spiders/ __init__.py
####2.1.1 items.py
类须要继承 scrapy.Item,爬取的主要目标就是从非结构性的数据源提取结构性数据,例如网页。 Scrapy提供Item类来知足这样的需求。 该项目中定义了在爬取元素构造的知乎用户属性和知乎用户关系两大块Item,为爬取后的数据转化为结构性数据,同时,也为后面的持久化作准备. ####2.1.2 pipelines.py :当Item在Spider中被收集以后,它将会被传递到Item Pipeline,一些组件会按照必定的顺序执行对Item的处理。git
每一个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并经过它执行一些行为,同时也决定此Item是否继续经过pipeline,或是被丢弃而再也不进行处理。github
如下是item pipeline的一些典型应用:web
process_item(self, item, spider) 每一个item pipeline组件都须要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被以后的pipeline组件所处理。
该项目中就在该类中实现把数据持久化到mango数据库中数据库
参数: item (Item 对象) – 被爬取的item spider (Spider 对象) – 爬取该item的spidercookie
import os from pymongo import MongoClient from zhihu.settings import MONGO_URI, PROJECT_DIR from zhihu.items import ZhihuPeopleItem, ZhihuRelationItem from zhihu.tools.async import download_pic class ZhihuPipeline(object): """ 存储数据 """ def __init__(self, mongo_uri, mongo_db, image_dir): self.mongo_uri = mongo_uri self.mongo_db = mongo_db self.image_dir = image_dir self.client = None self.db= None def process_item(self, item, spider): """ 处理item """ if isinstance(item, ZhihuPeopleItem): self._process_people(item) elif isinstance(item, ZhihuRelationItem): self._process_relation(item) return item
####2.1.3 settings.py
配置文件,提供爬虫系统参数的可配置化
####2.1.4 spiders 这个是一个包,能够定制本身的爬虫代码.如ZhihuSipder这个类就是知乎爬虫的启动类.dom
####2.2.1 CrawlSpider
这里采用CrawlSpider,这个继承了Spider的且,很是适合作全站数据爬取的类.scrapy
class ZhihuSipder(CrawlSpider): name = "zhihu" allowed_domains = ["www.zhihu.com"] start_url = "https://www.zhihu.com/people/hua-zi-xu-95"
简析上面的三个参数: 1.name:这个参数是每一个自定义爬虫必需要有的,惟一辨别你的自定义爬虫,name固然也是使用命令启动爬虫的一个决定因素.启动命令:scrapy crawl zhihu,其中的zhihu就是name属性. 2.allowed_domains:连接中必须包含的域名. 3.start_url:爬虫的入口地址,这里就是以我本人的知乎主页为入口. ####2.2.2 FormRequest作登录模块async
from scrapy.http import Request, FormRequest def post_login(self, response): """ 解析登录页面,发送登录表单 """ self.xsrf = Selector(response).xpath( '//input[@name="_xsrf"]/@value' ).extract()[0] return [FormRequest( 'https://www.zhihu.com/login/email', method='POST', meta={'cookiejar': response.meta['cookiejar']}, formdata={ '_xsrf': self.xsrf, 'email': 'xxxxxxxxx', 'password': 'xxxxxxxxx', 'remember_me': 'true'}, callback=self.after_login )]
####2.2.3 Requests and Responses Scrapy使用 Request 和 Response 对象爬取web站点。ide
通常来讲,Request 对象在spiders中被生成而且最终传递到 下载器(Downloader),下载器对其进行处理并返回一个 Response 对象, Response 对象还会返回到生成request的spider中。
全部 Request and Response 的子类都会实现一些在基类中非必要的 功能。它们会在 Request subclasses 和 Response subclasses 两部分进行详细的说明。 下面是Request构造函数
class Request(object_ref): def __init__(self, url, callback=None, method='GET', headers=None, body=None, cookies=None, meta=None, encoding='utf-8', priority=0, dont_filter=False, errback=None): self._encoding = encoding # this one has to be set first self.method = str(method).upper() self._set_url(url) self._set_body(body) assert isinstance(priority, int), "Request priority not an integer: %r" % priority self.priority = priority assert callback or not errback, "Cannot use errback without a callback" self.callback = callback self.errback = errback self.cookies = cookies or {} self.headers = Headers(headers or {}, encoding=encoding) self.dont_filter = dont_filter self._meta = dict(meta) if meta else None
特别注意:参数:dont_filter
dont_filter(boolean) – indicates that this request should not be filtered by the scheduler. This is used when you want to perform an identical request multiple times, to ignore the duplicates filter. Use it with care, or you will get into crawling loops. Default to False.
解释:scrapy url去重 Request对象参数的dont_filter=False,默认就是false 如程序所示,默认就是要进行url去重
show code:
def enqueue_request(self, request): //核心判断 注意 not 取否 if not request.dont_filter and self.df.request_seen(request): self.df.log(request, self.spider) return False dqok = self._dqpush(request) if dqok: self.stats.inc_value('scheduler/enqueued/disk', spider=self.spider) else: self._mqpush(request) self.stats.inc_value('scheduler/enqueued/memory', spider=self.spider) self.stats.inc_value('scheduler/enqueued', spider=self.spider) return True
ps: scrapy 中判断重复内容的方法(RFPDupeFilter)
github地址 该目录下的知乎爬虫项目,便可下载源码.
linux下命令窗口分配显示一遍查看使用说明,通常敲代码. 软件名: tmux
效果图: