爬虫框架:scrapy使用心得

文章目录


前言

有些时候我们需要采集大量数据时,我们需要程序的运行效率高,当然如果有时候不想写请求代码的时候,这些情况我都会向你推荐scrapy。当然如果你之前学过django,那么你上手会更快,因为设计的架构是差不多的。

一、scrapy是什么?

Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架。(更详细的理论介绍可以移步其他文章,会很详细,本文着重于实战)

二、使用步骤

1.安装和创建

1: 安装环境

python 复制代码
pip install scrapy

2: 创建爬虫工程文件

python 复制代码
scrapy startproject mySpider

3: 生成爬虫脚本

python 复制代码
scrapy genspider baidu https://www.baidu.com/ # scrapy genspider 文件名 网址

2.请求以及参数

  1. GET请求
python 复制代码
start_url = 'https://www.baidu.com/'
info = {'arg': 'arg'}

yield scrapy.Request(
            url=start_url,
            meta=info , # 传参数
            callback=self.parse_first,# 方法
            dont_filter=False # scrapy它会默认过滤相同请求
        )

def parse_first(self, response):
	arg = response.meta['arg']
  1. POST请求(有很多,这里运用笔者用的次数最多的)
python 复制代码
import json
from scrapy.http.request.json_request import JsonRequest
# 这里form_data 最好使用单引号
form_data = {'arg': 'arg'}
yield JsonRequest(
            url=url,
            body=json.dumps(form_data), # 对应requests库 requests.post里的参数 json=data
            method='POST',
            meta=info,
            callback=self.get_pro_price,
            dont_filter=True,
        )

3.代理池

  1. ua代理池,在middlewares.py文件添加类
python 复制代码
user_agent_list = ["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
        "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
        "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",............]
class RotateUserAgentMiddleware(UserAgentMiddleware):
    # 创建ua
    def process_request(self, request, spider):
        user_agent = random.choice(user_agent_list)
        if user_agent:
            request.headers.setdefault('User-Agent', user_agent)
            # print(f"User-Agent:{user_agent} is using.")
        return None

    def process_exception(self, request, exception, spider):
        error_info = f"spider:{spider.name} RotateUserAgentMiddleware has error with {exception}"
        # print(error_info)
        logging.error(error_info)
  1. ip代理池,在middlewares.py文件添加类
python 复制代码
class ProxyDownloaderMiddleware:

    def process_request(self, request, spider):
        """
        添加代理
        """
  1. 配置,在setting.py文件:
python 复制代码
DOWNLOADER_MIDDLEWARES = {
    "mySpider.middlewares.ProxyDownloaderMiddleware": 543,
    "mySpider.middlewares.RotateUserAgentMiddleware": 544,
} # 数值越低优先级越高

4.请求错误处理

  1. setting文件配置
python 复制代码
DUPEFILTER_DEBUG = True
# RETRY_HTTP_CODES = [429, 403, 504, 522,502,400] # 请求状态
# RETRY_TIMES = 5

# 请求失败重新请求50次
RETRY_ENABLED = True
RETRY_TIMES = 50

DOWNLOAD_TIMEOUT = 15  # 设置最大超时时间为15秒
  1. 个性化定制请求错误的逻辑,在middlewares.py文件添加类
python 复制代码
from scrapy.downloadermiddlewares.retry import RetryMiddleware
class CustomRetryMiddleware(RetryMiddleware):

    def process_response(self, request, response, spider):
        if response.status != 200:
        # 处理请求状态码不是200
            logger.error(request.url)
            logger.error(response.status)
            logger.error(request.meta)
        return response

    def process_exception(self, request, exception, spider):
        if self._is_max_retry(request):
        # 打印日志
            self._log_failed_request(request)

配置,在setting.py文件:

python 复制代码
DOWNLOADER_MIDDLEWARES = {
    "mySpider.middlewares.CustomRetryMiddleware": 544,
}

5.采集数据入库

  1. 定义item
python 复制代码
class SanItem(scrapy.Item):

    col1= scrapy.Field()  
    col2= scrapy.Field()
    col3= scrapy.Field()
	
	pass
  1. 数据写入mysql
python 复制代码
class MySQLSanPipeline(object):
    def __init__(self):
        self.connection = pymysql.connect(host='localhost',
                                          user='root',
                                          password='1234',
                                          database='test',
                                          charset='utf8mb4',
                                          cursorclass=pymysql.cursors.DictCursor)
        self.cursor = self.connection.cursor()
        self.data = []

    def open_spider(self, spider):
        pass

    def process_item(self, item, spider):
        self.data.append(
            (item['col1'], item['col2'], item['col3'], 
             )
        )
        if len(self.data) >= 100: # 数据量大于100 批量写入数据库
            self._write_to_db()
        return item

    def _write_to_db(self):
        # execute->改为了 executemany  支持多条数据批量传入数据库
        sql = """
              insert into sangon(col1,col2,col3
              ) values (%s,%s,%s)
              """
        self.cursor.executemany(
            sql, self.data
        )
        self.connection.commit()  # 把数据缓冲区的数据提交到数据库
        self.data.clear()  # 每次添加后清空data 避免重复添加数据

    def close_spider(self, spider):
        if len(self.data) >= 0:  # 如果还有残留的数据,但是因为不满100条没有传到数据库也要做好处理
            self._write_to_db()
        self.connection.close()
#=================记得在setting文件配置==================
ITEM_PIPELINES = {
    "mySpider.pipelines.MySQLSanPipeline": 300
}
  1. 更新MongoDB数据
python 复制代码
class MongoPipeline(object):

    def __init__(self, host, port, user, pwd, db, table):
        self.host = host
        self.port = port
        self.user = user
        self.pwd = pwd
        self.db = db
        self.table = table

    @classmethod
    def from_crawler(cls, crawler):
        HOST = crawler.settings.get('HOST')
        PORT = crawler.settings.get('PORT')
        USER = crawler.settings.get('USER')
        PWD = crawler.settings.get('PWD')
        DB = crawler.settings.get('DB')
        TABLE = crawler.settings.get('TABLE')
        return cls(HOST, PORT, USER, PWD, DB, TABLE)

    def open_spider(self, spider):
        self.conn = MongoClient("mongodb://{}:{}@{}:{}/{}".format(self.user, self.pwd, self.host, self.port, self.db))
        self.db_conn = self.conn[self.db]
        self.set_conn = self.db_conn[self.table]

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

    def process_item(self, item, spider):
        self.set_conn.update_one(
                        {'_id': item['_id'], },  # 查询条件:匹配具有特定_id的文档
                        {'$set': {
                            'col1': item['col1'],
                        }}  # 更新操作
                    )
        # 如果是列表字段内更新
        # {'id':id,'list':[{'code':'1','size':'s1'}]}
        self.set_conn.update_one(
                        {'_id': _id,'list.code':1},  # 查询条件:匹配具有特定_id的文档
                        {'$set': {'list.$.size': 's2'}}  # 更新操作
                    )
        return item
  #=================记得在setting文件配置==================
ITEM_PIPELINES = {
    "mySpider.pipelines.MongoPipeline": 300
}

6.日志及其他配置

  1. 日志配置
python 复制代码
import logging
import datetime
class MySpider(scrapy.Spider):
	custom_settings = {
	        'LOG_FILE': 'E:/Lu_zong_data/logs/log_{}_{}_{}_{}.txt'.format(
	            datetime.datetime.today().year,
	            datetime.datetime.today().month,
	            datetime.datetime.today().day,
	            datetime.datetime.today().hour),
	    }
#  写入日志文件信息 logging.info('测试')
  1. 终端运行太麻烦了,可以设置run.py
python 复制代码
from scrapy import cmdline

cmdline.execute('scrapy crawl baidu'.split())

总结

scrapy真是一个功能强大的爬虫框架,也建议结合crawlab爬虫管理平台,体感和操作效果会更好!

相关推荐
不会飞的鲨鱼3 小时前
【QQ音乐】sign签名| data参数加密 | AES-GCM加密 | webpack (下)
javascript·爬虫·python·webpack
lkx097884 小时前
爬虫--以爬取小说为例
爬虫·python
亿牛云爬虫专家2 天前
视觉分析开发范例:Puppeteer截图+计算机视觉动态定位
人工智能·爬虫·计算机视觉·爬虫代理·短视频·代理ip·小红书
灏瀚星空2 天前
【爬虫学习】Python数据采集进阶:从请求优化到解析技术实战
爬虫·python·学习
灏瀚星空3 天前
Tesseract 字库介绍与训练指南
经验分享·笔记·爬虫·python
不知道写什么的作者3 天前
Python爬虫实战:抓取百度15天天气预报数据
爬虫·python·百度
攻城狮7号3 天前
Python爬虫第22节- 结合Selenium识别滑动验证码实战
开发语言·人工智能·爬虫·python·滑动验证码·反爬虫
一个天蝎座 白勺 程序猿3 天前
Python爬虫(40)基于Selenium与ScrapyRT构建高并发动态网页爬虫架构:原理、实现与性能优化
爬虫·python·selenium
丶Xylon4 天前
Java爬虫,获取未来40天预测气象并写入Excel
java·爬虫·excel