Python爬虫-Scrapy的item loader

使用Scrapy爬取伯乐在线的文章,将爬取的数据保存到MySQL数据库中。

创建项目

使用Scrapy命令来创建项目。

梳理整体逻辑关系

我们先来分析一下整体的流程,我们想要获取,文章的图片,标题,发布的时间,详情页的链接,点赞数,收藏数,评论数。我们首先需要获取的是每一篇文章的详情页链接,图片地址,以及,下一页的地址。而后进入到文章的详情页,去获取文章的标题,发布日期,点赞数,评论数,收藏数,然后将这些数据保存到MySQL数据库中。OK!我们这样编写代码。

blog.py

class BlogSpider(scrapy.Spider):
    name = 'blog'
    allowed_domains = ['blog.jobbole.com']
    start_urls = ['http://blog.jobbole.com/all-posts/']
    def parse(self, response):
        item_list=response.xpath('//div[@class="post floated-thumb"]')
        for item in item_list:
            # 获取图片的链接
            image=item.xpath('.//div[@class="post-thumb"]/a/img/@src').extract_first('')
            # 获取详情页的链接
            url=item.xpath('.//a[@class="archive-title"]/@href').extract_first('')
            # 将详情页链接,以及图片链接传递给下一个方法
            yield  scrapy.Request(url=url,meta={'img':image},callback=self.get_detail_with_url)
            # 获取下一页的链接
        next_url=response.xpath('//a[@class="next page-numbers"]/@href').extract()
        if len(next_url)!=0:
            page_url=next_url[0]
            yield  scrapy.Request(url=page_url,callback=self.parse)
    def get_detail_with_url(self,response):
        # 接收图片的链接
        img=response.meta['img']
        print(img)
        # 获取标题
        title=response.xpath('//div[@class="entry-header"]/h1/text()').extract_first('')
        print(title)
        # 获取时间
        date_time=response.xpath('//div[@class="entry-meta"]/p[@class="entry-meta-hide-on-mobile"]/text()').extract_first('').strip()
        time=date_time.split('·')[0]
        print(time)
        # 详情页地址
        detail_url=response.url
        print(detail_url)
        # 获取点赞数
        dian_zan=response.xpath('//h10/text()').extract_first('')
        print(dian_zan)
        # 获取收藏数
        book_mark=response.xpath('//span[@class=" btn-bluet-bigger href-style bookmark-btn  register-user-only "]/text()').extract_first('')
        # 对数字进行单独的取出
        book_mark_array=book_mark.split(' ')
        book_mark_num=0
        if len(book_mark_array[1])!=0:
            book_mark_num=int(book_mark_array[1])
        print(book_mark_num)
        # 获取评论数
        comment=response.xpath('//a[@href="#article-comment"]/span/text()').extract_first('')
        # 对数字进行单独的取出
        comment_arrat=comment.split(' ')
        comment_num=0
        if len(comment_arrat[1])!=0:
            comment_num=int(comment_arrat[1])
        print(comment_num)
        print('------------------------------------------------------')
        item=JobboleItem()
        item['img']=img
        item['title']=title
        item['date_time']=time
        item['detail_url']=detail_url
        item['dian_zan']=dian_zan
        item['book_mark']=book_mark_num
        item['comment']=comment_num
        yield item

items.py

class JobboleItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    img=scrapy.Field()
    title=scrapy.Field()     
    date_time=scrapy.Field()
    detail_url=scrapy.Field()
    dian_zan=scrapy.Field()
    book_mark=scrapy.Field()
    comment=scrapy.Field()
    pass

建立MySQL数据库

pipelines.py

import pymysql
class JobbolePipeline(object):
#连接数据库
    def __init__(self):
        self.connect=pymysql.connect(host='localhost',user='root',password='123456',db='jobbole',port=3306)
        self.cursor=self.connect.cursor()
    def process_item(self, item, spider):
#往数据库里面写入数据
        self.cursor.execute('insert into blog(img,title,detail_url,time,dian_zan,book_mark,comment)VALUES ("{}","{}","{}","{}","{}","{}","{}")'
                            .format(item['img'],item['title'],item['detail_url'],item['date_time'],item['dian_zan'],item['book_mark'],item['comment']))
        self.connect.commit()
        return item
    def close_spider(self,spider):
        self.cursor.close()
        self.connect.close()

settings.py

BOT_NAME = 'jobbole'

SPIDER_MODULES = ['jobbole.spiders']
NEWSPIDER_MODULE = 'jobbole.spiders'

ROBOTSTXT_OBEY = False

ITEM_PIPELINES = {
   'jobbole.pipelines.JobbolePipeline': 300,
}

输入命令:scrapy crawl blog,打开数据库,刷新一下。

这样便算是完成了。但是我们可以看到,在blog.py中取出数据我们显得非常的麻烦,我们不仅要取出,然后剥离提取等等,感觉很混乱,所以,我们想要让这个代码顺序呈现的更加清晰,我们需要使用itemloader。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

blog.py

import scrapy
from ..items import JobboleItem
from ..items import  ArticleItemLoader

class BlogSpider(scrapy.Spider):
    name = 'blog'
    allowed_domains = ['blog.jobbole.com']
    start_urls = ['http://blog.jobbole.com/all-posts/']
    def parse(self, response):
        item_list=response.xpath('//div[@class="post floated-thumb"]')
        for item in item_list:
            # 获取图片的链接
            image=item.xpath('.//div[@class="post-thumb"]/a/img/@src').extract_first('')
            # 获取详情页的链接
            url=item.xpath('.//a[@class="archive-title"]/@href').extract_first('')
            # 将详情页链接,以及图片链接传递给下一个方法
            yield  scrapy.Request(url=url,meta={'img':image},callback=self.get_detail_with_url)
            # 获取下一页的链接
        next_url=response.xpath('//a[@class="next page-numbers"]/@href').extract()
        if len(next_url)!=0:
            page_url=next_url[0]
            yield  scrapy.Request(url=page_url,callback=self.parse)
    def get_detail_with_url(self,response):
     #创建itemLoader的实例化对象,需要传入两个参数
     #第一个值为item的实例化对象
     #第二个值为网页的源代码
        item_loader=ArticleItemLoader(item=JobboleItem(),response=response)
     #第一个值是设置field的名称
     #第二个值是xpath路径
        item_loader.add_xpath('title','//div[@class="entry-header"]/h1/text()')
        item_loader.add_value('img',[response.meta['img']])
        item_loader.add_xpath('date_time','//div[@class="entry-meta"]/p[@class="entry-meta-hide-on-mobile"]/text()')
        item_loader.add_value('detail_url',response.url)
        item_loader.add_xpath('dian_zan','//div[@class="post-adds"]//h10/text()')
        item_loader.add_xpath('book_mark','//span[@class=" btn-bluet-bigger href-style bookmark-btn  register-user-only "]/text()')
        item_loader.add_xpath('comment','//a[@href="#article-comment"]/span/text()')
        item=item_loader.load_item()
        yield item

items.py

import scrapy
from scrapy.loader import  ItemLoader
from scrapy.loader.processors import MapCompose,TakeFirst
import re
采用tmloader是数据分离数据的另外一种方式

def changeTitle(value):
    value='标题:'+value
    return value
def getNewTime(value):
    newTime=value.split('·')[0].strip()
    return newTime
def getNum(value):
    pattern=re.compile(r'\d+')
    result=re.findall(pattern,value)
    if result:
        return int(result[0])
    else:
        return 0
# 使用itemloader需要先继承Iitmloader
class ArticleItemLoader(ItemLoader):
  #设置输出内容的类型,TakeFirst()获取所有数据的第一条数据  
    default_output_processor=TakeFirst()
class JobboleItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    img=scrapy.Field(
        input_processor=MapCompose
    )
    title=scrapy.Field(       
        input_processor=MapCompose(changeTitle)
    )
    date_time=scrapy.Field(
        input_processor=MapCompose(getNewTime)
    )
    detail_url=scrapy.Field()
    dian_zan=scrapy.Field()
    book_mark=scrapy.Field(
        input_processor=MapCompose(getNum)
    )
    comment=scrapy.Field(
        input_processor=MapCompose(getNum)
    )
    pass

pipelines.py和settings.py 还是照写

输入命令:scrapy crawl blog ,按下回车键。进入数据库,点击刷新。

既然我们已经有了item,那为什么还有去使用itemloader呢,我们可以看到不管是使用xpath,都需要我们对数据进行正则的处理,会使我们的维护工作变得比较困难。使用itemloader是将提取和数据的过滤放到同一个函数当中,将数据的提取和数据的分离分成两个部分,使代码看起来更加的清晰,代码更加的整洁。也可以将数据的处理函数单独定义,也可以对一个数据使用多个处理的函数,这样的话对代码的重用有着非常好的实现。

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay丶萧邦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值