加载中...

初识Scrapy和使用


初识Scrapy和使用

了解Scrapy

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理 或存储历史数据等一系列的程序中。

安装Scrapy

使用pip直接安装

Windows:打开cmd,输入 pip install scrapy ,回车。

pip install scrapy

使用清华镜像

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy

其他镜像网址

清华大学镜像:https://pypi.tuna.tsinghua.edu.cn/simple/

阿里云:http://mirrors.aliyun.com/pypi/simple/

中科大镜像:https://pypi.mirrors.ustc.edu.cn/simple/

豆瓣镜像:http://pypi.douban.com/simple/

中科大镜像2:http://pypi.mirrors.ustc.edu.cn/simple/

创建Scrapy项目

 scrapy startproject 项目名称
 --- 例如:scrapy startproject spider_demo01

Scrapy项目构成

           spiders 
              __init__.py
              自定义的爬虫文件.py       ‐‐‐》由我们自己创建,是实现爬虫核心功能的文件
          __init__.py                  
          items.py                     ‐‐‐》定义数据结构的地方,是一个继承自scrapy.Item的类
          middlewares.py               ‐‐‐》中间件   代理
          pipelines.py  ‐‐‐》管道文件,里面只有一个类,用于处理下载数据的后续处理              
默认是300优先级,值越小优先级越高(1‐1000)                                        
          settings.py  ‐‐‐》配置文件  比如:是否遵守robots协议,User‐Agent定义等

创建爬虫文件

scrapy genspider 爬虫名字 网页的域名
--- 例如:scrapy genspider baidu https://www.baidu.com

运行爬虫文件

scrapy crawl 爬虫名称
--- 例如:scrapy crawl baidu

Scrapy的架构组成

  1. 引擎 ‐‐‐》自动运行,无需关注,会自动组织所有的请求对象,分发给下载器

  2. 下载器 ‐‐‐》从引擎处获取到请求对象后,请求数据

  3. spiders ‐‐‐》Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例 如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及 分析某个网页(或者是有些网页)的地方。

  4. 调度器 ‐‐‐》有自己的调度规则,无需关注

  5. 管道(Item pipeline) ‐‐‐》最终处理数据的管道,会预留接口供我们处理数据 当ItemSpider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。 每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行 一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。


    以下是item pipeline的一些典型应用:

    1. 清理HTML数据

    2. 验证爬取的数据(检查item包含某些字段)

    3. 查重(并丢弃)

    4. 将爬取结果保存到数据库中

Scrapy的工作原理

Scrapy的工作原理

  1. 引擎向spidersurl
  2. 引擎将要爬取的url给调度器
  3. 调度器会将url生成请求对象放入到指定的队列中
  4. 从队列中出队一个请求
  5. 引擎将请求交给下载器进行处理
  6. 下载器发送请求获取互联网数据
  7. 下载器将数据返回给引擎
  8. 引擎将数据再次给到spiders
  9. spiders通过xpath解析该数据,得到数据或者url
  10. spiders将数据或者url给到引擎
  11. 引|擎判断该数据还是url,是数据,交给管道(itempipeline)处理,是url交给调度器处理

相关案例

PS:相关案例仅用于学习使用!!!

汽车之家

# 使用前注释robot协议或者改成False
import scrapy

class CarSpider(scrapy.Spider):
    name = "car"
    allowed_domains = ["cn.58.com"]
    start_urls = ["https://cn.58.com/dazhong/?PGTID=0d30001d-008d-2709-b9ed-9477389f1bd7"]

    def parse(self, response):
        # response.text 字符串
        # content = response.text
        content = response.xpath("//div[@id='list']//img[@class='info_pic']/@data-original")
        for i in content:
            print(i.extract())

当当网

# 该文件用于读取一些数据,并未做过多的修饰
import scrapy
from ..items import SpiderDemo03Item


class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["category.dangdang.com", "product.dangdang.com"]
    start_urls = ["https://category.dangdang.com/cp01.43.19.00.00.00.html"]
    base_url = 'https://category.dangdang.com/pg'
    page = 1

    def parse(self, response):
        li_list = response.xpath("//ul[@id='component_59']/li")

        for li in li_list:
            # 第一张图片的src可以使用
            src = li.xpath(".//img/@data-original").extract_first()
            if src:
                src = src
            else:
                src = li.xpath(".//img/@src").extract_first()
            name = li.xpath(".//img/@alt").extract_first()
            price = li.xpath(".//p[@class='price']/span[@class='search_now_price']/text()").extract_first()
            book = SpiderDemo03Item(src=src, name=name, price=price)
            # 将数据交给管道文件
            yield book

        # https://category.dangdang.com/pg2-cp01.43.19.00.00.00.html
        # 爬取100页
        # if self.page < 100:
        #     self.page += 1
        #     url = self.base_url + str(self.page) + '-cp01.43.19.00.00.00.html'
        #     yield scrapy.Request(url=url, callback=self.parse)
# items.py
class SpiderDemo03Item(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    src = scrapy.Field()
    name = scrapy.Field()
    price = scrapy.Field()
    time = scrapy.Field()
# pipelines.py
import urllib.request

class SpiderDemo03Pipeline:
    # 打开文件
    def open_spider(self, spider):
        self.fp = open('dang.json', 'w', encoding='utf-8')

    def process_item(self, item, spider):
        # 写入到json文件
        self.fp.write(str(item))

        return item

    # 关闭文件
    def close_spider(self, spider):
        self.fp.close()


# 多管道下载
# 记得在当前目录下面添加books文件夹
class dangPipeline:
    def process_item(self, item, spider):
        url = 'http:'+item.get('src')
        filename = './books/' + item.get('name') + '.jpg'
        urllib.request.urlretrieve(url, filename)
        return item
# settings.py
# 需要添加下图的管道解开注释即可
ITEM_PIPELINES = {
   # 下载图片的管道
   # "spider_demo03.pipelines.dangPipeline": 301,
   # 保存json文件的管道
   "spider_demo03.pipelines.SpiderDemo03Pipeline": 300,
}

CrawlSpider

CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发 送请求

所以,如果有需要跟进链接的需求,意思就是爬取了网页之后,需要提取链接再次爬取,使用CrawlSpider是非常 合适的

案例:读书网数据入库

创建项目:

scrapy startproject spider_demo

创建爬虫类:

scrapy genspider ‐t crawl read www.dushu.com

配置数据库:

# settings.py
DB_HOST = 'localhost'
DB_PORT = 3306
DB_USER = 'root'
DB_PASSWORD = '123456'
DB_NAME = 'spider'
DB_CHARSET = 'utf8'

# 关闭robot协议
ROBOTSTXT_OBEY = False

# 开启日志输出文件,可以不选择开启
LOG_FILE = "log.log"

编写爬虫类文件:

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import SpiderDemo04Item


class ReadSpider(CrawlSpider):
    name = "read"
    allowed_domains = ["www.dushu.com"]
    start_urls = ["https://www.dushu.com/book/1617_1.html"]

    # 这里需要编写匹配的html地址,可以去官网参考
    rules = (
        Rule(LinkExtractor(
            allow=r"/book/1617_\d+"),
            callback="parse_item",
            follow=True),
    )

    def parse_item(self, response):
        img_list = response.xpath("//div[@class='book-info']//a/img")
        for i in img_list:
            src = i.xpath("./@data-original").extract_first()
            name = i.xpath("./@alt").extract_first()
            book = SpiderDemo04Item(name=name, src=src)
            yield book
# items.py
class SpiderDemo04Item(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    src = scrapy.Field()

编写管道文件:

# 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
# 加载配置文件
from scrapy.utils.project import get_project_settings
import pymysql


class SpiderDemo04Pipeline:
    def open_spider(self, spider):
        self.fp = open('dushu.json', 'w', encoding='utf-8')

    def process_item(self, item, spider):
        self.fp.write(str(item))
        return item

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


class MysqlPipeline:
    # 链接MySQL
    def open_spider(self, spider):
        settings = get_project_settings()
        self.conn = pymysql.connect(
            host=settings['DB_HOST'],
            port=settings['DB_PORT'],
            user=settings['DB_USER'],
            password=settings['DB_PASSWORD'],
            database=settings['DB_NAME'],
            charset=settings['DB_CHARSET']
        )
        self.cursor = self.conn.cursor()
        print('链接数据库成功')

    def process_item(self, item, spider):
        sql = 'insert into book(name,src) values(%s,%s)'
        self.cursor.execute(sql, (item['name'], item['src']))
        self.conn.commit()
        return item

    # 关闭链接
    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()
        print('关闭数据库链接')

记得在配置文件打开管道:

ITEM_PIPELINES = {
    "spider_demo04.pipelines.MysqlPipeline": 301,
    "spider_demo04.pipelines.SpiderDemo04Pipeline": 300,
}

Scrapy的post请求

import scrapy
import json


class DushuSpider(scrapy.Spider):
    name = "dushu"
    allowed_domains = ["fanyi.baidu.com"]
    start_urls = ["https://fanyi.baidu.com/sug/"]

    # 需要使用功能 start_requests 方法
    def start_requests(self):
        url = "https://fanyi.baidu.com/sug/"
        data = {
            "kw": "hello"
        }
        yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse_second)

    def parse_second(self, response):
        content = response.text
        obj = json.loads(content)
        print(obj)

代理

  1. settings.py中,打开一个选项
DOWNLOADER_MIDDLEWARES = { 
    'postproject.middlewares.Proxy': 543, 
} 
  1. middlewares.py中写代码
def process_request(self, request, spider): 
    request.meta['proxy'] = 'https://113.68.202.10:9999' 
    return None

文章作者:
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 !