Scrapy 学习手记

Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。--网络介绍

罗列推荐看的网址:

按教程安装完(这里推荐且只推荐使用conda方式安装,而非其它,诸如pip)后,常用的命令:

scrapy startproject projectName
scrapy genspider spiderName "xxx.html"
scrapy crawl spiderName
scrapy shell "url"

整体而言,要做的就是:先设计自己要爬取的item的结构体(items.py),同时设计对应的spider.py,在爬虫代码中,将爬到的内容填入item的字段后,将item交给pipeline处理,pipeline将这些爬取到的数据存储到文件,或者是数据库中。
具体流程也一并给出如下:

  1. 爬虫引擎获得初始请求开始抓取。
  2. 爬虫引擎开始请求调度程序,并准备对下一次的请求进行抓取。
  3. 爬虫调度器返回下一个请求给爬虫引擎。
  4. 引擎请求发送到下载器,通过下载中间件下载网络数据。
  5. 一旦下载器完成页面下载,将下载结果返回给爬虫引擎。
  6. 引擎将下载器的响应通过中间件返回给爬虫进行处理。
  7. 爬虫处理响应,并通过中间件返回处理后的items,以及新的请求给引擎。
  8. 引擎发送处理后的 items 到项目管道,然后把处理结果返回给调度器,调度器计划处理下一个请求抓取。
  9. 重复该过程(继续步骤1),直到爬取完所有的 url 请求。

建立爬虫项目之后,给出爬虫代码模板,第一个代码是最基本的爬虫,但是,这份代码实在是太简单了,只能爬一两个页面,如果是要爬多页数据,页里又有多条数据,可以下面的第二份代码:

"""第一份代码"""
import scrapy
class QuotesSpider(scrapy.Spider):
    name = "quotes"
    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)

"""第二份代码"""
class MySpider(scrapy.Spider):
    name = 'myspider'
    def start_requests(self):
        urls = ['https://www.xxx.com']
        for url in urls:
            yield scrapy.Request(url=url, callback=self.url_parse)

    def url_parse(self, response):
        """
        url_parser目的是获取目录页面上一个个页面的网址
        """
        urls = response.xpath('...')
        for url in urls:
            # 对每个页面进行数据提取
            yield scrapy.Request(url, callback=self.data_parse)

        next_page = response.xpath('...').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.url_parse)


    def data_parse(self, response):
        """
        从最终的页面获取数据
        """
        data = response.xpath('...')
        l = ItemLoader(item=MyItem(), response=response)
        l.add_value('data', data)
        yield l.load_item()

其中name即当前爬虫的名称,也是今后启动它的唯一标识。爬虫回自动执行start_requests(self)函数,按代码对url发起请求,这是比较自定义的形式。如果为了偷懒,也可以不重写start_requests(),而是用下面这份代码来代替:

name = "quotes"
start_urls = [
    'http://quotes.toscrape.com/page/1/',
    'http://quotes.toscrape.com/page/2/',
]

这些就不赘述。总的来说,start_urls负责发起请求,请求之后的结果,会放入response函数中,并运行parse(self, response)函数,我们的目的就是从response中,利用各种解析工具,比如css或者xpath或者正则表达式来提取内容,提取之后,可以放入自定义的item,丢入pipeline来持久化(比如存入数据库),也可以直接parse完写入文件。

先在items.py 定义自己想要的item:

import scrapy
class Product(scrapy.Item):
    name = scrapy.Field()
    price = scrapy.Field()
    stock = scrapy.Field()
    last_updated = scrapy.Field(serializer=str)

然后在spider中将item_load到pipeline中:

from scrapy.loader import ItemLoader
from myproject.items import Product

l = ItemLoader(item=Product(), response=response)
l.add_value('name', response.xpath('...'))
l.add_value('price', response.xpath('...'))
l.add_value('stock', response.xpath('...'))
l.add_value('last_updated', response.xpath('...'))
yield l.load_item()

那么就需要在pipelines.py中实现对这些items的处理的pipeline,对于不同的spider,可以用它们的name来进行区分处理:

class MyPipeline(object):
    def open_spider(self, spider):
        if spider.name == 'spider1':
            self.file = open('file1.txt', 'a+')
       elif spider.name == 'spider2':
            self.file = open('file2.txt', 'a+')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + '\n'
        self.write(line)
        return item

    def close_spider(self, spider):
        self.file.close()

最后在settings.py中注册这个pipeline,让其真正投入生产线:

ITEM_PIPELINES = {
   'myproject.pipelines.MyPipeline': 300,
}

这里规定的数字,决定了组件运行的顺序,数字越小,越先执行。

实践相关问题:

可以参考这里
常见的有防止被目标网站禁止(ban):

  • 使用user agent池,轮流选择之一来作为user agent。
  • 禁止cookies(参考settings.py的COOKIES_ENABLED),有些站点会使用cookies来发现爬虫的轨迹。
  • 设置下载延迟(2或更高)。参考DOWNLOAD_DELAY设置。
  • 如果可行,使用Google cache来爬取数据,而不是直接访问站点。
  • 使用IP池。例如免费的 Tor项目 或付费服务ProxyMesh
  • 使用高度分布式的下载器(downloader)来绕过禁止(ban),您就只需要专注分析处理页面。这样的例子有: Crawlera

其中,设置随机请求头的问题,这个问题非常建议参考博文:一行代码搞定Scrapy的随机UserAgent
简而言之,只需两步:

  • pip安装模块 pip install scrapy-fake-useragent
  • 在settings.py加入这个模块,让它进行UserAgent的自动设置。
DOWNLOADER_MIDDLEWARES = {
     # 关闭默认的UA方法,并开启自己的UA方法
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, 
    'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400,  
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345