码迷,mamicode.com
首页 > 其他好文 > 详细

scrapy框架介绍

时间:2018-10-31 23:24:24      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:功能   sts   null   commit   intel   修改   高性能   pip3   web   

一,介绍

  Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍。所谓的框架就是一个已经被集成了各种功能(高性能异步下载,队列,分布式,解析,持久化等)的具有很强通用性的项目模板。对于框架的学习,重点是要学习其框架的特性、各个功能的用法即可。

二,安装

Linux:

      pip3 install scrapy

 

  Windows:

      a. pip3 install wheel

      b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

      c. 进入下载目录,执行 pip3 install Twisted?17.1.0?cp35?cp35m?win_amd64.whl

      d. pip3 install pywin32

      e. pip3 install scrapy

三.基本使用

1.创建项目:scrapy startproject 项目名称

项目目录结构:

project_name/
   scrapy.cfg:
   project_name/
       __init__.py
       items.py
       pipelines.py
       settings.py
       spiders/
           __init__.py

scrapy.cfg   项目的主配置信息。(真正爬虫相关的配置信息在settings.py文件中)
items.py     设置数据存储模板,用于结构化数据,如:Django的Model
pipelines    数据持久化处理
settings.py  配置文件,如:递归的层数、并发数,延迟下载等
spiders      爬虫目录,如:创建文件,编写爬虫解析规则

2.创建爬虫应用程序

      cd project_name(进入项目目录)

      scrapy genspider 应用名称 爬取网页的起始url (例如:scrapy genspider qiubai www.qiushibaike.com)

3.编写爬虫文件

在步骤2执行完毕后,会在项目的spiders中生成一个应用名的py爬虫文件,文件源码如下:

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

class QiubaiSpider(scrapy.Spider):
    name = qiubai #应用名称
    #允许爬取的域名(如果遇到非该域名的url则爬取不到数据)
    allowed_domains = [https://www.qiushibaike.com/]
    #起始爬取的url
    start_urls = [https://www.qiushibaike.com/]

     #访问起始URL并获取结果后的回调函数,该函数的response参数就是向起始的url发送请求后,获取的响应对象.该函数返回值必须为可迭代对象或者NUll 
     def parse(self, response):
        print(response.text) #获取字符串类型的响应内容
        print(response.body)#获取字节类型的相应内容

4.设置修改settings.py配置文件相关配置

修改内容及其结果如下:
19行:USER_AGENT = Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 #伪装请求载体身份

22行:ROBOTSTXT_OBEY = False  #可以忽略或者不遵守robots协议

5.执行爬虫程序:scrapy crawl  应用名称

应用名称就是spiders中生成一个应用名的py中的 QiubaiSpider 类中的name属性

四.数据持久化

1,第一种,在parse方法中直接return时

class QiubaiSpider(scrapy.Spider):
    name = qiubai
    allowed_domains = [www.qiushibaike.com/text]
    start_urls = [https://www.qiushibaike.com/text/]  # 注意手动修改http为https

    def parse(self, response):
        # print(response)
        div_list = response.xpath("//div[@id=‘content-left‘]/div")
        data_list = []
        for div in div_list:
            # xpath之后返回的结果市Selector对象,需要调用extract方法,获取数据
            # author = div.xpath("./div/a[2]/h2/text()")[0].extract()
            author = div.xpath("./div/a[2]/h2/text()").extract_first()
            # xpath之后返回的列表中只有一个元素时,可以使用extract_first
            content = div.xpath("./a/div/span/text()").extract_first()
            # 持久化存储
            dict_info = {
                "author": author.strip("\n ") if author else "",
                "content": content.strip("\n ") if content else ""
            }
            print(dict_info)
            data_list.append(dict_info)
        return data_list

此时持久化可采用下面的方式:

切记切换到项目目录下在执行

执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储
    scrapy crawl qiubai -o qiubai.json
    scrapy crawl qiubai -o qiubai.xml
    scrapy crawl qiubai -o qiubai.csv

2,使用scrapy中的pipelines持久化

scrapy框架中已经为我们专门集成好了高效、便捷的持久化操作功能,我们直接使用即可。要想使用scrapy的持久化操作功能,我们首先来认识如下两个文件:

items.py:数据结构模板文件。定义数据属性。
    pipelines.py:管道文件。接收数据(items),进行持久化操作。

持久化流程:
    1.爬虫文件爬取到数据后,需要将数据封装到items对象中。
    2.使用yield关键字将items对象提交给pipelines管道进行持久化操作。
    3.settings.py配置文件中开启管道

ex:将糗事百科首页中的段子和作者数据爬取下来,然后进行持久化存储

(1)手动打开文件存储

爬虫文件: spider目录下的qiushi.py

class QiubaiSpider(scrapy.Spider):
    name = qiubai
    allowed_domains = [www.qiushibaike.com/text]
    start_urls = [https://www.qiushibaike.com/text/]  # 注意手动修改http为https

    def parse(self, response):
        # print(response)
        div_list = response.xpath("//div[@id=‘content-left‘]/div")
        data_list = []
        for div in div_list:
            # xpath之后返回的结果市Selector对象,需要调用extract方法,获取数据
            # author = div.xpath("./div/a[2]/h2/text()")[0].extract()
            author = div.xpath("./div/a[2]/h2/text()").extract_first()
            author = author.strip("\n") if author else ""
            # xpath之后返回的列表中只有一个元素时,可以使用extract_first
            content = div.xpath("./a/div/span//text()").extract_first()
            content = content.strip("\n") if content else ""
            # 持久化存储
            item = FirstSiteItem()
            item["author"] = author
            item["content"] = content
            yield item  # 提交item到管道文件(pipelines.py)

items文件:items.py

import scrapy

class FirstSiteItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    author = scrapy.Field()  # 存储作者
    content = scrapy.Field()  # 存储内容

管道文件:pipelines.py

class FirstSitePipeline(object):

    def __init__(self):
        self.fp = None   #定义一个文件描述符属性

    #下列都是在重写父类的方法:

    #开始爬虫时,执行一次
    def open_spider(self, spider):
        print("爬虫开始")
        self.fp = open("qiubai2.txt", "w", encoding="utf-8")

    #因为该方法会被执行调用多次,所以文件的开启和关闭操作写在了另外两个只会各自执行一次的方法中
    def process_item(self, item, spider):
       #将爬虫程序提交的item进行持久化存储
        self.fp.write("{}:{}\n".format(item["author"] or "", item["content"] or ""))
        return item

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

配置文件:settings.py

#开启管道
ITEM_PIPELINES = {
‘first_site.pipelines.FirstSitePipeline‘: 300,
‘first_site.pipelines.MysqlPipeline‘: 200, # 数字越小优先级越高
‘first_site.pipelines.RedisPipeline‘: 400, # 数字越小优先级越高
}

(2)存储在mysql

class MysqlPipeline(object):

    def __init__(self):
        self.conn = None
        self.cursor = None

    def open_spider(self, spider):
        print("mysql爬虫开始")
        self.conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="", db="qiushi", charset="utf8")
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        sql = "insert into _qiushi values(%s, %s)"
        try:
            self.cursor.execute(sql, [item["author"] or "", item["content"] or ""])
            self.conn.commit()
        except Exception as e:
            print(e)
            self.conn.rollback()  # 回滚
        return item

    def close_spider(self, spider):
        print("mysql爬虫结束")
        self.cursor.close()
        self.conn.close()

(2)存储在redis

import redis

class RedisPipeline(object):

    def __init__(self):
        self.r = None

    def open_spider(self, spider):
        print("redis爬虫开始")
        self.r = redis.Redis()

    def process_item(self, item, spider):
        data_info = {
            author: item[author],
            content: item[content]
        }
        self.r.lpush(qiushi_data, data_info)
        return item

    def close_spider(self, spider):
        print("redis爬虫结束")

五.Scrapy递归爬取多页数据

ex:爬取煎蛋网妹子图片,爬取n页

jiandan.py:

# -*- coding: utf-8 -*-
import scrapy
import base64
from jiandanmeizi.items import JiandanmeiziItem


class JiandanSpider(scrapy.Spider):
    name = jiandan
    # allowed_domains = [‘jandan.net/ooxx/page-1#comments‘]
    start_urls = [http://jandan.net/ooxx/page-1#comments/]

    page_num = 2  # 循环从第2页开始
    page_url = "http://jandan.net/ooxx/page-%s#comments"

    def parse(self, response):
        li_list = response.xpath("//div[@id=‘comments‘]/ol//li[contains(@id, ‘comment-‘)]")
        for li in li_list:
            img_str = li.xpath("./div/div/div[2]/p/span/text()").extract_first()
            img_url = self.get_img_url(img_str)
            if img_url.endswith("gif"):
                continue
            # 递归爬取数据:callback参数的值为回调函数(将url请求后,得到的相应数据继续进行parse解析),递归调用parse函数
            yield scrapy.Request(url=img_url, callback=self.parse_img)  # 注意一定要yield

        if self.page_num <= 20:
            url = self.page_url % self.page_num
            print(url)
            yield scrapy.Request(url=url, callback=self.parse)
            self.page_num += 1

    def parse_img(self, response):
        item = JiandanmeiziItem()
        item["data"] = response.body
        item["url"] = response.url
        yield item

    def get_img_url(self, e):
        """
        该方法可用于解出煎蛋网加密图片的真正src
        e为span标签中的随机字符串
        :return:
        """
        return "http:" + base64.b64decode(e).decode()

items.py:

import scrapy

class JiandanmeiziItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    data = scrapy.Field()
    url = scrapy.Field()
技术分享图片
import os

class JiandanmeiziPipeline(object):

    def open_spider(self, spider):
        print("爬取煎蛋妹子图开始")
        if not os.path.exists("jiandan_img"):
            os.mkdir("jiandan_img")

    def process_item(self, item, spider):
        file_path = os.path.join("jiandan_img", item["url"].split("/")[-1])
        print(file_path)
        with open(file_path, "wb") as f:
            f.write(item["data"])
        return item

    def close_spider(self, spider):
        print("爬取煎蛋妹子图结束")
pipelines.py
USER_AGENT = Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36

# Obey robots.txt rules
ROBOTSTXT_OBEY = False


ITEM_PIPELINES = {
   jiandanmeizi.pipelines.JiandanmeiziPipeline: 300,
}

 

scrapy框架介绍

标签:功能   sts   null   commit   intel   修改   高性能   pip3   web   

原文地址:https://www.cnblogs.com/glh-ty/p/9886365.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!