Python Scrapy 爬虫框架实例(一)

之前有介绍 scrapy 的相关知识,但是没有介绍相关实例,在这里做个小例,供大家参考学习。

注:后续不强调python 版本,默认即为python3.x。

爬取目标这里简单找一个图片网站,获取图片的先关信息。

该网站网址: http://www.58pic.com/c/

创建项目终端命令行执行以下命令 

scrapy startproject AdilCrawler


命令执行后,会生成如下结构的项目。


执行结果如下


如上图提示,cd 到项目下,可以执行 scrapy genspider example example.com 命令,创建 名为example,域名为example.com 的 爬虫文件。


编写items.py

这里先简单抓取图片的作者名称、图片主题等信息。

# -*- coding: utf-8 -*-
# Define here the models for your scraped items

# See documentation in:# https://doc.scrapy.org/en/latest/topics/items.htmlimport scrapyclass AdilcrawlerItem(scrapy.Item):

# define the fields for your item here like:# name = scrapy.Field()   

author = scrapy.Field() # 作者   

theme = scrapy.Field() # 主题

编写spider文件

进入AdilCrawler目录,使用命令创建一个基础爬虫类:

scrapy genspider  thousandPic www.58pic.com#  thousandPic为爬虫名,www.58pic.com为爬虫作用范围


执行命令后会在spiders文件夹中创建一个thousandPic.py的文件,现在开始对其编写:

# -*- coding: utf-8 -*-import scrapy# 爬虫 小试class ThousandpicSpider(scrapy.Spider):

    name ='thousandPic'    allowed_domains = ['www.58pic.com']

    start_urls = ['http://www.58pic.com/c/']

    def parse(self, response):

        '''       

          查看页面元素

          /html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()

          因为页面中 有多张图,而图是以 /html/body/div[4]/div[3]/div[i]  其中i  为变量 作为区分的 ,所以为了获取当前页面所有的图

          这里 不写 i 程序会遍历 该 路径下的所有 图片。

        '''

        # author 作者

        # theme  主题

        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()

        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()

        # 使用 爬虫的log 方法在控制台输出爬取的内容。       

        self.log(author)

        self.log(theme)

        # 使用遍历的方式 打印出 爬取的内容,因为当前一页有20张图片。foriinrange(1, 21):

        print(i,' **** ',theme[i - 1],': ',author[i - 1] )


 执行命令,查看打印结果

scrapy crawl thousandPic


结果如下,其中DEBUG为 log 输出。


代码优化

引入 itemAdilcrawlerItem

# -*- coding: utf-8 -*-import scrapy# 这里使用 import 或是 下面from 的方式都行,关键要看 当前项目在pycharm的打开方式,是否是作为一个项目打开的,建议使用这一种方式。import AdilCrawler.items as items# 使用from 这种方式,AdilCrawler 需要作为一个项目打开。# from AdilCrawler.items import AdilcrawlerItemclass ThousandpicSpider(scrapy.Spider):

    name ='thousandPic'    allowed_domains = ['www.58pic.com']

    start_urls = ['http://www.58pic.com/c/']

    def parse(self, response):

        '''       

          查看页面元素

          /html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()

          因为页面中 有多张图,而图是以 /html/body/div[4]/div[3]/div[i]  其中i  为变量 作为区分的 ,所以为了获取当前页面所有的图

          这里 不写 i 程序会遍历 该 路径下的所有 图片。

        '''       

        item = items.AdilcrawlerItem()

        # author 作者# theme  主题        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()

        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()

        item['author'] = author

        item['theme']  = theme

        return item

再次运营爬虫,执行结果如下


保存结果到文件

执行命令如下

scrapy crawl thousandPic -o items.json

会生成如图的文件


再次优化,使用 ItemLoader 功能类

使用itemLoader ,以取代杂乱的extract()和xpath()。

代码如下: 

# -*- coding: utf-8 -*-

import scrapyfromAdilCrawler.items

import AdilcrawlerItem

# 导入 ItemLoader 功能类fromscrapy.loaderimport ItemLoader

# optimize  优化

# 爬虫项目优化

class ThousandpicoptimizeSpider(scrapy.Spider):

    name ='thousandPicOptimize'    allowed_domains = ['www.58pic.com']

    start_urls = ['http://www.58pic.com/c/']

    def parse(self, response):

        '''

          查看页面元素

          /html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()

          因为页面中 有多张图,而图是以 /html/body/div[4]/div[3]/div[i]  其中i  为变量 作为区分的 ,所以为了获取当前页面所有的图

          这里 不写 i 程序会遍历 该 路径下的所有 图片。

        '''

        # 使用功能类 itemLoader,以取代 看起来杂乱的 extract() 和 xpath() ,优化如下

        i = ItemLoader(item = AdilcrawlerItem(),response = response )

        # author 作者# theme  主题        i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()')

        i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()')

        return i.load_item()


编写pipelines文件

 默认pipelines.py 文件

# -*- coding: utf-8 -*-# Define your item pipelines here#

# Don't forget to add your pipeline to the ITEM_PIPELINES setting

# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

class Adilcrawler1Pipeline(object):

    def process_item(self, item, spider):

        return item


优化后代码如下


# -*- coding: utf-8 -*-# Define your item pipelines here#

# Don't forget to add your pipeline to the ITEM_PIPELINES setting

# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

import json

class AdilcrawlerPipeline(object):

    '''       

    保存item数据

    '''

        def__init__(self):

                self.filename = open('thousandPic.json','w')

        def process_item(self, item, spider):

                #  ensure_ascii=False 可以解决 json 文件中 乱码的问题。

                text = json.dumps(dict(item), ensure_ascii=False) +',\n'

                #  这里是一个字典一个字典存储的,后面加个 ',\n' 以便分隔和换行。       

                self.filename.write(text)

                return item

        def close_spider(self,spider):

                self.filename.close()


settings文件设置

修改settings.py配置文件

找到pipelines 配置进行修改

# Configure item pipelines


# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html

# ITEM_PIPELINES = {

#    'AdilCrawler.pipelines.AdilcrawlerPipeline': 300,

# }

# 启动pipeline 必须将其加入到“ITEM_PIPLINES”的配置中

# 其中根目录是tutorial,pipelines是我的pipeline文件名,TutorialPipeline是类名

ITEM_PIPELINES = {

    'AdilCrawler.pipelines.AdilcrawlerPipeline': 300,

}

# 加入后,相当于开启pipeline,此时在执行爬虫,会执行对应的pipelines下的类,并执行该类相关的方法,比如这里上面的保存数据功能。


执行命令

scrapy crawl thousandPicOptimize

执行后生成如下图文件及保存的数据



使用CrawlSpider类进行翻页抓取

使用crawl 模板创建一个 CrawlSpider

执行命令如下

scrapy genspider -t crawl thousandPicPaging www.58pic.com

items.py 文件不变,查看 爬虫 thousandPicPaging.py 文件

# -*- coding: utf-8 -*-

import scrapyfromscrapy.linkextractorsimport LinkExtractorfromscrapy.spidersimport CrawlSpider, Ruleclass ThousandpicpagingSpider(CrawlSpider):

    name ='thousandPicPaging'    allowed_domains = ['www.58pic.com']

    start_urls = ['http://www.58pic.com/']

    rules = (

        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),

    )

    def parse_item(self, response):

        i = {}

        #i['domain_id'] = response.xpath('//input[@id="sid"]/@value').extract()

        #i['name'] = response.xpath('//div[@id="name"]').extract()

        #i['description'] = response.xpath('//div[@id="description"]').extract()

return i


修改后如下

# -*- coding: utf-8 -*-import scrapy

# 导入链接规则匹配类,用来提取符合规则的连接fromscrapy.linkextractorsimport LinkExtractor

# 导入CrawlSpider类和Rulefromscrapy.spidersimport CrawlSpider, Ruleimport AdilCrawler.items as itemsclass ThousandpicpagingSpider(CrawlSpider):

    name ='thousandPicPaging'    allowed_domains = ['www.58pic.com']

    # 修改起始页地址start_urls = ['http://www.58pic.com/c/']

    # Response里链接的提取规则,返回的符合匹配规则的链接匹配对象的列表# http://www.58pic.com/c/1-0-0-03.html  根据翻页连接地址,找到 相应的 正则表达式  1-0-0-03  -> \S-\S-\S-\S\S  而且 这里使用 allow# 不能使用 restrict_xpaths ,使用 他的话,正则将失效page_link = LinkExtractor(allow='http://www.58pic.com/c/\S-\S-\S-\S\S.html', allow_domains='www.58pic.com')

    rules = (

        # 获取这个列表里的链接,依次发送请求,并且继续跟进,调用指定回调函数处理

        Rule(page_link, callback='parse_item', follow=True),

        # 注意这里的 ',' 要不会报错   

        )

    # 加上这个 方法是为了 解决 parse_item() 不能抓取第一页数据的问题 parse_start_url 是 CrawlSpider() 类下的方法,这里重写一下即可

def parse_start_url(self, response):

        i = items.AdilcrawlerItem()

        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()

        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()

        i['author'] = author

        i['theme'] = theme

        yield i

    # 指定的回调函数def parse_item(self, response):

        i = items.AdilcrawlerItem()

        author = response.xpath('/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()').extract()

        theme = response.xpath('/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()').extract()

        i['author'] = author

        i['theme'] = theme

        yieldi


再次执行 

scrapy crawl thousandPicPaging


查看执行结果,可以看到是有4页的内容


再次优化引入 ItemLoader

# -*- coding: utf-8 -*-

import scrapy

# 导入链接规则匹配类,用来提取符合规则的连接

fromscrapy.linkextractorsimport LinkExtractor

# 导入CrawlSpider类和Rulefromscrapy.loader

import ItemLoaderfromscrapy.spiders

import CrawlSpider, Rule

import AdilCrawler.items as items

class ThousandpicpagingopSpider(CrawlSpider):

    name ='thousandPicPagingOp'    allowed_domains = ['www.58pic.com']

    # 修改起始页地址start_urls = ['http://www.58pic.com/c/']

    # Response里链接的提取规则,返回的符合匹配规则的链接匹配对象的列表# http://www.58pic.com/c/1-0-0-03.html  根据翻页连接地址,找到 相应的 正则表达式  1-0-0-03  -> \S-\S-\S-\S\S  而且 这里使用 allow# 不能使用 restrict_xpaths ,使用 他的话,正则将失效page_link = LinkExtractor(allow='http://www.58pic.com/c/\S-\S-\S-\S\S.html', allow_domains='www.58pic.com')

    rules = (

        # 获取这个列表里的链接,依次发送请求,并且继续跟进,调用指定回调函数处理

        Rule(page_link, callback='parse_item', follow=True),

        # 注意这里的 ',' 要不会报错

    )

    # 加上这个 方法是为了 解决 parse_item() 不能抓取第一页数据的问题 parse_start_url 是 CrawlSpider() 类下的方法,这里重写一下即可

def parse_start_url(self, response):

        i = ItemLoader(item = items.AdilcrawlerItem(),response = response )

        i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()')

        i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()')

        yield  i.load_item()

        # 指定的回调函数def parse_item(self, response):

        i = ItemLoader(item = items.AdilcrawlerItem(),response = response )

        i.add_xpath('author','/html/body/div[4]/div[3]/div/a/p[2]/span/span[2]/text()')

        i.add_xpath('theme','/html/body/div[4]/div[3]/div/a/p[1]/span[1]/text()')

        yieldi.load_item()


执行结果是一样的。

最后插播一条 在线正则表达式测试 工具的广告,地址: http://tool.oschina.net/regex/

应用如下


至此,简单完成了一个网站的简单信息的爬取。后面还会有其他内容的介绍~

如果你要觉得对你有用的话,请不要吝惜你打赏,这将是我无尽的动力,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 18,936评论 17 410
  • 本文为《爬着学Python》系列第四篇文章。从本篇开始,本专栏在顺序更新的基础上,会有不规则的更新。 在Pytho...
    SyPy阅读 2,496评论 4 11
  • 呵呵!作为一名教python的老师,我发现学生们基本上一开始很难搞定python的装饰器,也许因为装饰器确实很难懂...
    TypingQuietly阅读 19,545评论 26 186
  • 本地仓库是远程仓库的一个缓冲和子集,当你构建Maven项目的时候,首先会从本地仓库查找资源,如果没有,那么Mave...
    NicholasZhen阅读 1,081评论 0 1
  • 不过在这一点上周逸也犯了以貌取人的错误,这朱悟能能有今天这样的地位,虽然靠了一些关系,但真正倚仗的还是他自身二十年...
    可可豆子阅读 275评论 0 5