scrapy数据解析与持久化存储

1.数据解析

-使用response.xpath("xpath表达式")

-scrapy封装的xpath和etree中的xpath区别:

  -scrapy中的xpath直接将定位到的标签中存储的值或者属性值取出,返回的Selector对象数据值是存储在Selector对象的data属性,需要调用extract、extract_first()取出

2.基于管道的持久化存储

 -基于终端指令的持久化存储

 -要求:该种方式只可以将parse方法的返回值存储到本地指定后缀的文本文件中

 -执行命令:scrapy crawl 爬虫文件名 -0 filePath

-基于管道的持久化存储

 -在爬虫文件中进行解析(如上图所示)

 -在item.pyt中定义相关属性

  -步骤1中解析了title和context字段数据,那就就定义这两个属性

 -在爬虫文件中将解析到的数据存储封装到Item类型的对象中

 -将Item类型的对象提交给管道

 

 -在管道文件(pipelines.py)中,接收爬虫文件提交过来的Item类型对象,且对其进行任意形式的持久化操作

 

 -在配置文件中开启管道机制

  300表示:管道嘞优先级,数值越小,优先级越高

 

3.基于管道实现数据备份

将爬取到的数据存储到不同载体中

-将数据分别存储到mysql和redis中

 -管道类文件中的一个管道类表示怎样的一组操作?

  -一个管道类对应一种形式的持久化存储操作。如果将数据存储到不同的载体中就需要使用多个管道类

# 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
import pymysql
from redis import Redis

class SpidersPipeline:

    fp = None
    #重写父类两个方法
    def open_spider(self,spider):
        print("我是open,在爬虫开始的时候执行一次")
        self.fp = open('test.txt','w',encoding='utf-8')

    def close_spider(self, spider):
        print("close,在爬虫结束的时候执行一次")
        self.fp.close()


    # 该方法用来接收item对象  一次只能接收一个item,说明该方法会被调用很多次
    # 参数Item:就是接收到的item对象
    def process_item(self, item, spider):
        self.fp.write(item["title"] + item["context"]+'\n')
        # 将item存储到本地文件
        return item


#将数据存储到mysql中
class MysqlPileLine(object):
    conn = None
    cursor = None
    def open_spider(self,spider):
        self.conn = pymysql.Connect(host='127.0.0.1',port='3306',user='root',password='123456',db='testdb',charset='utf-8')

    def process_item(self,item,spider):
        self.cursor = self.conn.cursor()
        sql = 'insert into test02 values ("%s","%s")'%(item['title'],item['context'])

        #事物处理
        try:
            self.cursor.execute(sql)  # 执行sql
            self.conn.commit()  #提交
        except Exception as e:
            self.conn.rollback()  # 回退
        return item
    def close_spider(self,spider):
        self.cursor.close()  # 关闭游标
        self.conn.close()  # 关闭连接

#将数据写入redis

class RedidPileLine(object):
    conn = None
    def open_spider(self,spider):
        self.conn = Redis(host="127.0.0.1",port=6379)
        print(self.conn)
    def process_item(self,item,spider):
        # 报错:将redis模块版本指定为2.10.6  pip install -U redis==2.10.6
        self.conn.lpush("testdb",item)

 

4.scrapy手动请求发送实现全站数据爬取

 -yield scrapy.Requests(url,callback):get

-yield scrapy.FromRequests(url,callback,formdata):post

为什么start_url列表的url会被自动进行get请求发送?

  -因为列表中的url其实是start_requests这个父类方法实现的get请求发送 

def start_requests(self):
    dor u in self.start_urls:
        yield scrapy.Request(url=u,callback=self.parse)

如何将start_urls中的url默认进行post请求的发送?

#重写start_requests方法即可
def start_requests(self):
    for u in self.start_urls:
        yield scrapy.FormRequest(url=u,callback=self.parse)

5.scrapy手动请求传参数

  -实现方式

    -scrappy.Requests(url,callback,meta)

      -meta是一个字典,可以将meta传递给callback

    -claaback取出meta:

      -response.meta

import scrapy


from moviePro.items import MovieproItem

class MovieSpider(scrapy.Spider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['http://www.4567tv.tv/index.php/vod/show/id/5.html']
    
    #定义一个通用的url模板
    url = 'http://www.4567tv.tv/index.php/vod/show/id/5/page/%d.html'
    pageNum = 2

    def parse(self, response):
        li_list = response.xpath('//ul[@class="stui-vodlist clearfix"]/li')
        for li in li_list:
            title = li.xpath('./div/a/@title').extract_first()
            detail_url = 'https://www.4567tv.tv' + li.xpath('./div/a/@href').extract_first()

            #实例化
            item = MovieproItem()
            item['title'] = title

            # 对详情页url发起请求
            #meta作用:可以将字典传递给callback
            yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={'item':item})
        if self.pageNum < 5:
            new_url = format(self.url%self.pageNum)
            self.pageNum += 1
            yield scrapy.Request(url=new_url,callback=self.parse)


    # 被作用于解析详情页的数据
    def parse_detail(self,response):
        #接收传递过来的item
        item = response.meta['item']
        desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]').extract_first()
        item['desc'] = desc
        yield item

 

posted @ 2023-06-02 00:04  小青年て  阅读(168)  评论(0)    收藏  举报