Scrapy+selenium完成动态网站爬虫框架封装 | Python 主题月

本文正在参加「Python主题月」,详情查看 活动链接

前言

scrapy是一个非常成熟的爬虫框架,里面几乎封装好了开发者所需要的所有模块,例如:request,代理,日志,url自动去重等等,一些不太满意的模块也是稍加修改就行。但scrapy只能爬静态网页,如果需要爬动态渲染的网页的话还需要借助第三方组件,例如selenium或者splash.

为什么选择selenium

selenium和splash都是非常优秀的动态网页渲染工具。但selenium与splash相比,主要有以下几个有点:

  1. selenium可以直接在浏览器运行,就像真是的用户操作一样。
  2. selenium的文档更加详细,国内的教程也多,splash教程真是少的可怜。
  3. selenium支持的模拟用户行为的操作命令更加全面详细,splash的部分用户操作行为也有,但具体怎么使用,通过他们的手册我是没看懂。

综上几点还是选择selenium好一点,但并不是splash全无优点,我之前写过PHP的爬虫,用的就是splash,个人意见:如果没有特别复杂的交互,用splash还是可以的,splash提供的api,我们只需要把请求头,代理和url传给splash,也能得到渲染好的html.

本文要实现的功能

  1. Scrapy的安装
  2. 配置selenium
  3. sqlalchemy完成数据入库

Scrapy的安装

安装scrapy

在终端输入 pip install scrapy

创建scrapy项目

  1. 创建项目,命令:scrapy startproject 项目名称
  2. 创建爬虫文件,命令:scrapy genspider 文件名称 域名

我执行的

scrapy startproject spider
复制代码
scrapy genspider douban douban.com
复制代码

生成的项目目录就是这样的

spider
    spider
        spiders
            __init__.py
            douban.py
        __init__.py
        items.py
        middlewares.py
        piplines.py
        settings.py
    scrapy.cfg
复制代码

添加相关目录

spider
    spider
        common  # 公共配置文件目录 
            __init__.py
            conf.py # 数据库配置信息
        models # mysql model类
            __init__.py  
        spiders
            __init__.py
            douban.py
        __init__.py
        items.py
        middlewares.py
        piplines.py
        settings.py
    scrapy.cfg
复制代码

配置selenium

浏览器驱动的安装就不说了,因为每个系统安装方式都不一样,网上各个系统的安装方法都很详细,也不是很难。

引入selenium包

pip安装selenium包

pip install selenium
复制代码

更改代码

spider/spiders/douban.py

import scrapy

from selenium import webdriver
# 使用无头浏览器
from selenium.webdriver.chrome.options import Options  
# 无头浏览器设置
chorme_options = Options()
chorme_options.add_argument("--headless")
chorme_options.add_argument("--disable-gpu")

class DoubanSpider(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['douban.com']
    start_urls = ['https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0']

    # 实例化一个浏览器对象
    def __init__(self):
        self.browser = webdriver.Chrome(options=chorme_options)
        super().__init__()

    def parse(self, response):
        print(response.body)
        pass

    def close(self, spider):
        print('爬虫结束,关闭浏览器')
        self.browser.quit()
复制代码

settings.py配置文件里更改一些配置

# 更改用户代理(也可以设置成动态切换,个人感觉没必要)
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36'
# 关闭遵从robots协议
ROBOTSTXT_OBEY = False
# 打开下载中间件
DOWNLOADER_MIDDLEWARES = {
   'spider.middlewares.SpiderDownloaderMiddleware': 543,
}
# 数据处理管道
ITEM_PIPELINES = {
   'spider.pipelines.SpiderPipeline': 300,
}
复制代码

middlewares.py中间件文件修改:
SpiderDownloaderMiddleware类的process_response方法修改,用浏览器驱动加载url

def process_response(self, request, response, spider):
    """
    三个参数:
    # request: 响应对象所对应的请求对象
    # response: 拦截到的响应对象
    # spider: 爬虫文件中对应的爬虫类的实例对象, 可以通过这个参数拿到中的一些属性或方法
    """
    spider.browser.get(url=request.url)
    # 等待加载,  可以用显示等待来优化.
    time.sleep(1)  
    row_response = spider.browser.page_source
    # 参数url指当前浏览器访问的url(通过current_url方法获取), 在这里参数url也可以用request.url
    return HtmlResponse(url=spider.browser.current_url, body=row_response, encoding="utf8",
                        request=request)  
复制代码

至此,selenium的配置就完了

引入sqlalchemy完成数据入库

在Python中,最有名的ORM框架是SQLAlchemy,文档齐全使用方便,同时为高效和高性能的数据库访问设计,实现了完整的企业级持久模型。

添加数据库连接配置文件

数据库配置文件spider/common/conf.py

class conf:
    mysql = {
        # 数据库本地环境配置信息
        'dev': {
            'host': '127.0.0.1',
            'database': 'test',
            'user': 'user',
            'password': 'passord',
            'port': 3306,
        },
        # 测试服务器配置信息
        'test': {
            'host': '127.0.0.1',
            'database': 'test',
            'user': 'user',
            'password': 'passord',
            'port': 3306,
        },
        # 线上服务器配置信息
        'prod': {
            'host': '127.0.0.1',
            'database': 'test',
            'user': 'user',
            'password': 'passord',
            'port': 3306,
        },
    }
}
复制代码

运行环境配置文件
spider/common/env.py

# coding:utf-8
"""
环境标识(不可随意更改,此文件不上传到git)
    本地环境 dev
    测试环境 test
    线上环境 prod
"""

class env:
    env = 'dev'
复制代码

添加数据库连接

spider/models/__init__.py文件里添加数据库连接

# -*- coding: utf-8 -*-
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from spider.common.conf import conf
from spider.common.env import env

Base = declarative_base()
env = env.env
mysql = conf.mysql[env]
engine = create_engine(
    url="mysql+pymysql://{user}:{password}@{host}/{database}".format(
        user=mysql['user'],
        password=mysql['password'],
        host=mysql['host'],
        database=mysql['database']),
    encoding='UTF-8',
    pool_size=5,  # 连接池大小
    max_overflow=10,  # 超过连接池大小外最多创建的连接
    pool_timeout=30,  # 池中没有线程最多等待的时间,否则报错
    pool_pre_ping=True
)
Session = sessionmaker(bind=engine)()
复制代码

建立数据表模型

spider/models目录下添加Movie.py文件

from sqlalchemy import Column, String, Integer, DateTime
from spider.models import Base


class Movie(Base):
    # 表公共信息配置
    __tablename__ = "movie"

    # 表字段定义
    id = Column(Integer, primary_key=True)
    title = Column(String(100), comment='影片名')
    created_at = Column(DateTime, comment='添加时间')
    updated_at = Column(DateTime, comment='更新时间')
复制代码

添加item字段

items.py添加MovieItem

import scrapy

class SpiderItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    pass

class MovieItem(scrapy.Item):
    title = scrapy.Field()
    pass
复制代码

更改爬虫程序

spider/spiders/douban.py添加数据解析

import scrapy

from selenium import webdriver
# 使用无头浏览器
from selenium.webdriver.chrome.options import Options
# 无头浏览器设置
from spider.items import MovieItem

chorme_options = Options()
chorme_options.add_argument("--headless")
chorme_options.add_argument("--disable-gpu")

class DoubanSpider(scrapy.Spider):
    name = 'douban'
    allowed_domains = ['douban.com']
    start_urls = ['https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0']

    # 实例化一个浏览器对象
    def __init__(self):
        self.browser = webdriver.Chrome(options=chorme_options)
        super().__init__()

    def parse(self, response):
        for value in response.css('.list-wp>.list>a'):
            item = MovieItem()
            item['title'] = value.css('.cover-wp>img::attr(alt)').extract_first()
            yield item
        pass

    def close(self, spider):
        print('爬虫结束,关闭浏览器')
        self.browser.quit()
复制代码

管道入库

pipelines.py将数据添加到数据库

import datetime

from spider.models import Session
from spider.models.Movie import Movie


class SpiderPipeline:

    """
    爬虫被打开的时候执行
    :param spider:
    :return:
    """
    def open_spider(self, spider):
        print("爬虫开始....")

    """
    爬虫有item传过来的时候会被调用
    :param item:
    :param spider:
    :return:
    """
    def process_item(self, item, spider):
        try:
            data = Movie(title=item['title'], created_at=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                         updated_at=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            Session.add(data)
            Session.commit()
        except():
            Session.rollback()
            return None

    """
    爬虫关闭的时候被调用
    :param spider:
    :return:
    """
    def close_spider(self, spider):
        # 关闭数据库连接
        Session.close()
        print("爬虫结束,关闭数据库连接")
复制代码

总结

至此一个简单的爬虫程序就完成了,上面所有的请求都是走selenium组件的,有些静态网页是不需要的,在中间件里判断一下就行了。本篇只是简单的封装,完善的爬虫程序还需要设置代理,考虑分布式,增量爬虫,这里就不深入介绍了。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享