scrapy框架

一、框架介绍

Scrapy是适用于Python的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
image
scrapy框架的工作流程如下流程图
image

  1. Scrapy Engine(引擎):负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
  2. Scheduler(调度器):它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
  3. Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理。
  4. Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)。
  5. Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
  6. Downloader Middlewares(下载中间件):一个可以自定义扩展下载功能的组件。
  7. Spider Middlewares(Spider中间件):一个可以自定扩展和操作引擎和Spider中间通信的功能组件。

以上内容来自百度搜索引擎,纯属为了扩展自己的知识面,没有故意侵权的想法

二、安装步骤

在terminal执行以下命令安装或者在pycharm的下载第三方模块的位置搜索安装也可以的,甚至可以源码安装

pip3.8 install  scrapy

Mac或Linux系统直接执行以上命令就顺利安装,但是Windows有时会出现安装失败的情况,这时候,我可以以下步骤针对性的解决问题即可

第一步:pip3 install wheel #安装后,便支持通过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs
第二步:pip3 install lxml
第三步:pip3 install pyopenssl
第四步:下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
第五步:下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
第六步:执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
第七步:pip3 install scrapy

三、创建项目

pycharm不支持在它可视化界面创建scrapy但是我们有cmd终端,我们在终端用命令创建项目再用pycharm打开即可

scrapy startproject myfirstscrapy     # 第一步:创建项目   等同于 创建Django
cd myfirstscrapy                      # 第二步:CD到scrapy项目路径
scrapy genspider cnblogs www.cnblogs.com  # 创建爬虫   等同于 创建app

image
在D盘根目录下就会有咱刚刚创建的scrapy项目咯
image
创建好了的项目可以在pycharm里打开进行开发
image
项目创建成功之后,命令方式运行

scrapy crawl cnblogs

用绿色三角形点击运行的话先建run.py 文件
然后呢,在该文件里写如下代码

from scrapy.cmdline import execute

execute(['scrapy', 'crawl', 'cnblogs','--nolog'])  # --nolog指的是不输出日志

四、项目目录结构

image

五、项目配置

1. 基本配置

#项目名字,整个爬虫名字
BOT_NAME = "firstscrapy"
# 爬虫存放位置
SPIDER_MODULES = ["firstscrapy.spiders"]
NEWSPIDER_MODULE = "firstscrapy.spiders"
# 是否遵循爬虫协议,一般都设为False
ROBOTSTXT_OBEY = False
# 用户代理
USER_AGENT = "firstscrapy (+http://www.yourdomain.com)"
# 日志输出级别(当前是只输出报错信息)
LOG_LEVEL='ERROR'
# 默认请求头
DEFAULT_REQUEST_HEADERS = {
   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
   'Accept-Language': 'en',
}
# 爬虫中间件
SPIDER_MIDDLEWARES = {
    'cnblogs.middlewares.CnblogsSpiderMiddleware': 543,
}
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
    'cnblogs.middlewares.CnblogsDownloaderMiddleware': 543,
}
# 持久化配置
ITEM_PIPELINES = {
    'cnblogs.pipelines.CnblogsPipeline': 300,
}

2. 提高爬虫效率的配置

#1 增加并发:默认16
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改
CONCURRENT_REQUESTS = 100
值为100,并发设置成了为100。
#2 降低日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:
LOG_LEVEL = 'INFO'
# 3 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:
COOKIES_ENABLED = False
# 4 禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:
RETRY_ENABLED = False
# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:
DOWNLOAD_TIMEOUT = 10 超时时间为10s

六、解析数据

1. 解析方法

# response对象有css方法和xpath方法
css中写css选择器
xpath中写xpath选择
xpath取文本内容
'.//a[contains(@class,"link-title")]/text()'
xpath取属性
'.//a[contains(@class,"link-title")]/@href'
css取文本
'a.link-title::text'
css取属性
'img.image-scale::attr(src)'
.extract_first()  取一个
.extract()        取所有

2. 解析案例

用xpath解析cnblogs

import scrapy


class CnblogsSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["www.cnblogs.com"]
    start_urls = ["https://www.cnblogs.com/"]


    def parse(self, response):
        """xpath解析"""
        article_list = response.xpath('//*[@id="post_list"]/article')
        for article in article_list:
            title = article.xpath('.//div/a/text()').extract_first()
            author_img = article.xpath('.//div//img/@src').extract_first()
            author_name = article.xpath('.//footer//span/text()').extract_first()
            desc_old = article.xpath('.//p/text()').extract()
            desc = desc_old[0].replace('\n', '').replace(' ', '')
            if not desc:
                desc = desc_old[1].replace('\n', '').replace(' ', '')
            url = article.xpath('.//div/a/@href').extract_first()
            info_demo = """
                1.文章题目:%s
                2.作者头像:%s
                3.作者姓名:%s
                4.文章简介:%s
                5.文章地址:%s
                """
            print(info_demo % (title, author_img, author_name,desc,url))

用css选择器解析cnblogs

import scrapy


class CnblogsSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["www.cnblogs.com"]
    start_urls = ["https://www.cnblogs.com/"]

    def parse(self, response):
        """css解析"""
        article_list = response.css('article.post-item')
        for article in article_list:
            title = article.css('div.post-item-text>a::text').extract_first()
            author_img = article.css('div.post-item-text img::attr(src)').extract_first()
            author_name = article.css('footer span::text').extract_first()
            desc_old = article.css('p.post-item-summary::text').extract()
            desc = desc_old[0].replace('\n', '').replace(' ', '')
            if not desc:
                desc = desc_old[1].replace('\n', '').replace(' ', '')
            url = article.css('div.post-item-text>a::attr(href)').extract_first()
            info_demo = """
                1.文章题目:%s
                2.作者头像:%s
                3.作者姓名:%s
                4.文章简介:%s
                5.文章地址:%s
                """
            print(info_demo % (title, author_img, author_name,desc,url))

七、持久化方案

  1. items.py 写类
  2. 爬虫中,实例化得到对象(必须放在for内部),放到对象中数据,yield item对象
  3. pipline中写 类中3个方法
open_spider :打开资源
close_spider:关闭资源
process_item
  1. 配置文件中配置

第一步:在items.py中写一个类

import scrapy


class MyfirstscrapyItem(scrapy.Item):
    title = scrapy.Field()
    author_img = scrapy.Field()
    author_name = scrapy.Field()
    desc = scrapy.Field()
    url = scrapy.Field()
    content = scrapy.Field()

第二步:在piplines.py中写代码,写一个类:open_spide,close_spider,process_item

  1. open_spider:开启爬虫会触发
  2. close_spider:爬完会触发
  3. process_item:每次要保存一个对象会触发
import pymysql


class MyfirstscrapyMySqlPipeline:
    def open_spider(self, spider):
        self.conn = pymysql.connect(
            user='root',
            password="mire123",
            host='127.0.0.1',
            database='cnblogs',
            port=3306,
        )
        self.cursor = self.conn.cursor()

    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()

    def process_item(self, item, spider):  # article
        sql = '''INSERT INTO article (title,author_img,author_name,`desc`,url,content) VALUES(%s,%s,%s,%s,%s,%s);'''
        self.cursor.execute(sql,
                            args=[item['title'], item['author_img'], item['author_name'], item['desc'], item['url'],
                                  item['content']
                                  ])
        self.conn.commit()
        return item

第三步:配置文件配置

ITEM_PIPELINES = {
    "myfirstscrapy.pipelines.MyfirstscrapyMySqlPipeline": 300,  # 数字越小优先级越大
}

第四步:在解析方法parse中yield item对象

import scrapy
from myfirstscrapy.items import MyfirstscrapyItem
from scrapy.http.request import Request


class CnblogsSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["www.cnblogs.com"]
    start_urls = ["https://www.cnblogs.com/"]

    # 解析出下一页地址,继续爬取
    def parse(self, response):
        article_list = response.xpath('//*[@id="post_list"]/article')
        for article in article_list:
            item = MyfirstscrapyItem()
            title = article.xpath('.//div/a/text()').extract_first()
            item['title'] = title
            author_img = article.xpath('.//div//img/@src').extract_first()
            item['author_img'] = author_img
            author_name = article.xpath('.//footer//span/text()').extract_first()
            item['author_name'] = author_name
            desc_old = article.xpath('.//p/text()').extract()
            desc = desc_old[0].replace('\n', '').replace(' ', '')
            if not desc:
                desc = desc_old[1].replace('\n', '').replace(' ', '')
            item['desc'] = desc
            url = article.xpath('.//div/a/@href').extract_first()
            item['url'] = url
            yield Request(url=url, callback=self.parser_detail, meta={'item': item})  # 爬完后执行的解析方法

        next = 'https://www.cnblogs.com' + response.css('div.pager>a:last-child::attr(href)').extract_first()
        yield Request(url=next, callback=self.parse)

    # 解析详情的方法
    def parser_detail(self, response):
        content = response.css('#cnblogs_post_body').extract_first()
        item = response.meta.get('item')
        if content:
            item['content'] = content
        else:
            item['content'] = '没查到'
        yield item

八、在scrapy框架加proxy、cookie、header、selenium

在下载中间件类里面加

    ## 1 加代理
    def get_proxy(self):
        import requests
        res = requests.get('http://127.0.0.1:5010/get/').json()
        if res.get('https'):
            return 'https://' + res.get('proxy')
        else:
            return 'http://' + res.get('proxy')  # http://202.110.67.141:9091

    def process_request(self, request, spider):
        # 加代理
        print(request)
        request.meta['proxy'] = self.get_proxy()
        # 加cookie
        request.cookies['name'] = 'lqz'
        # 加请求头
        request.headers['referer'] = 'http://www.lagou.com'
        # 加动态生成user_agent
        # fake_useragent模块  第三方模块需要下载pip install fake_useragent
        from fake_useragent import UserAgent
        ua = UserAgent()
        request.headers['User-Agent'] = str(ua.random)
        print(request.headers)
        # 爬取下一页这种地址---》用selenium,但是文章详情,就用原来的
        if 'sitehome/p' in request.url:
            spider.bro.get(request.url)
            # print(spider.bro.page_source)
            from scrapy.http.response.html import HtmlResponse
            response = HtmlResponse(url=request.url, body=bytes(spider.bro.page_source, encoding='utf-8'))
            return response
        else:
            return None

tip:
加的代理是自己搭建的免费代理池
所以启动爬虫项目之前先启动代理池
获取随机免费代理,然后咱们得项目才能用的到
启动服务端和客户端的命令也贴一下这里吧

# 如果已经具备运行条件, 可用通过proxyPool.py启动。
# 程序分为: schedule 调度程序 和 server Api服务

# 启动调度程序
python proxyPool.py schedule

# 启动webApi服务
python proxyPool.py server
posted @ 2023-03-29 15:38  阿丽米热  阅读(69)  评论(0编辑  收藏  举报
Title