https://github.com/Python3WebSpider/Python3WebSpider/blob/master/13.2-Scrapy%E5%85%A5%E9%97%A8.md
安装Scrapy 需要先安装 lxml pyOpenSSL Twisted PyWin32
安装好上述模块以后 pip install Scrapy
验证安装及创建一个Scrapy项目 如果提示权限问题 可以加sudo运行该命令
创建spider
执行完毕后 spiders文件夹中多了一个quotes,py的文件
name: 每个项目唯一的名字 用来区分spider
allowed_domains : 允许爬取的域名 如果初始或者后续请求链接不是这个域名下的请求会被过滤掉
start_urls : 包含了spider在启动时爬取的url列表 初始请求由它来定义
parse() : start_urls中的链接请求完成下载执行后 的结果会作为唯一的参数传递给这个方法 该方法负责解析返回的响应 提取数据 或进一步生成要处理的请求
创建Item
item保存爬取数据的容器
需要继承 scrapy.item 类 定义类型为Field的字段
修改刚刚创建的项目中的 item.py 文件 定义三个字段
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class QuoteItem(scrapy.Item):
#define the fields for your item here like:
# name = scrapy.Field()
text = scrapy.Field()
author = scrapy.Field()
tags = scrapy.Field()
解析Response
修改 spider.py中的parse()函数 并使用 Item
import scrapy
class QuotesSpider(scrapy.Spider):
name = 'quotes'
allowed_domains = ['quotes.toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
quotes = response.css('.quote')
for quote in quotes:
item = QuoteItem()
item['text'] = quote.css('.text::text').extract_first()
item['author'] = quote.css('.author::text').extract_first()
item['tags'] = quote.css('.tags.tag::text').extract()
yield item
抓取下一页内容的Request
构造请求时需要用到scarpy.Request 传递两个参数 url:请求链接
callback: 请求完成之后回调函数 引擎会将响应作为参数传递给这个回调 函数,回调函数做解析或生成新的请求
import scrapy
from tutorial.items import QuoteItem
class QuotesSpider(scrapy.Spider):
name = 'quotes'
allowed_domains = ['quotes.toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
quotes = response.css('.quote')
for quote in quotes:
item = QuoteItem()
item['text'] = quote.css('.text::text').extract_first()
item['author'] = quote.css('.author::text').extract_first()
item['tags'] = quote.css('.tags .tag::text').extract() #之前在.tags.tag之间没加空格 爬出来的tags就为空
yield item
next = response.css('.pager.next a::attr("href")').extract_first()
url = response.urljoin(next) # 为什么是response.urljoin() response不是响应的结果吗 不应该是一个base_url.urljoin()吗
yield scrapy.Request(url=url,callback=self.parse)###self.parse不用加括号吗 parse()不是一个方法吗
进入目录 scrapy crawl quotes 运行
爬取到的部分数据
保存爬取结果到文件
可以保存为多种文件格式
scrapy crawl quotes -o quotes.json
scrapy crawl quotes -o quotes.csv
scrapy crawl quotes -o quotes.marshal
scrapy crawl quotes -o quotes.xml
scrapy crawl quotes -o quotes.pickle
scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quotes.csv
使用Item Pipeline
如果对爬取结果进行一些操作 比如筛选啊 清洗啊 就可以使用Item Pipeline
使用Item Pipeline只需在一个类中实现 process_item() 方法 该方法有两个参数 一个是item 每次Spider生成的item都会作为参数传递过来 另一个参数是spider的实例
修改项目中的pipeline.py文件
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
import pymongo
class TextPipeline:
def __init__(self):
self.limit = 50
def process_item(self, item, spider):
if(item['text']):
if len(item['text']) > self.limit:
item['text'] = item['text'][0:self.limit].rstrip()+'...' ##[0:self.limit] 中间是冒号
return item
else:
return DropItem('Missing Text')
class MongoPipeline:
def __init__(self,mongo_uri,mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls,crawler):
'''
从settings.py文件传参数
'''
return cls(
mongo_uri = crawler.settings.get('MONGO_URI'),
mongo_db = crawler.settings.get('MONGO_DB')
)
def open_spider(self,spider): ###我感觉这个函数用不到spider对象啊
'''
建立mongodb数据库
'''
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db] ###这里是中括号
def process_item(self,item,spider):
'''
实现Item Pipeline 需要在一个类中实现这个方法
'''
name = item.__class__.__name__ #实例调用__class__属性时会指向该实例对应的类,然后可以再去调用其它类属性,类属性由类调用
self.db[name].insert(dict(item)) ###用name 作为collection 的名字 想mongodb中插入数据
return item
def closed(self):
self.db.close()
classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。
class A(object):
bar = 1
def func1(self):
print ('foo')
@classmethod
def func2(cls):
print ('func2')
print (cls.bar)
cls().func1() # 调用 foo 方法
A.func2() # 不需要实例化
在settings.py文件中增加如下内容
ITEM_PIPELINES={
'tutorial.pipelines.TextPipeline':300,
'tutorial.pipelines.MongoPipeline':400, ###键名是类名 键值为优先级 数字越小 优先级越高
}
MONGO_URI='localhost'
MONGO_DB='tutorial'
重新运行 scrapy crawl quotes
mongodb中成功插入数据