Scrapy框架介绍之Puppeteer渲染的使用


Posted in Python onJune 19, 2020

1、Scrapy框架

Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛。
框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便。
Scrapy 使用了 Twisted'twɪstɪd异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。

Scrapy框架介绍之Puppeteer渲染的使用

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

2、Puppeteer渲染

Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包,用来模拟 Chrome 浏览器的运行。
为了爬取js渲染的html页面,我们需要用浏览器来解析js后生成html。在scrapy中可以利用pyppeteer来实现对应功能。
完整代码 ?scrapy-pyppeteer.zip
我们需要新建项目中middlewares.py文件(./项目名/middlewares.py)

import websockets
from scrapy.http import HtmlResponse
from logging import getLogger
import asyncio
import pyppeteer
import logging
from concurrent.futures._base import TimeoutError
import base64
import sys
import random

pyppeteer_level = logging.WARNING
logging.getLogger('websockets.protocol').setLevel(pyppeteer_level)
logging.getLogger('pyppeteer').setLevel(pyppeteer_level)

PY3 = sys.version_info[0] >= 3


def base64ify(bytes_or_str):
  if PY3 and isinstance(bytes_or_str, str):
    input_bytes = bytes_or_str.encode('utf8')
  else:
    input_bytes = bytes_or_str

  output_bytes = base64.urlsafe_b64encode(input_bytes)
  if PY3:
    return output_bytes.decode('ascii')
  else:
    return output_bytes


class ProxyMiddleware(object):
  USER_AGENT = open('useragents.txt').readlines()

  def process_request(self, request, spider):
    # 代理服务器
    proxyHost = "t.16yun.cn"
    proxyPort = "31111"
    # 代理隧道验证信息
    proxyUser = "username"
    proxyPass = "password"

    request.meta['proxy'] = "http://{0}:{1}".format(proxyHost, proxyPort)

    # 添加验证头
    encoded_user_pass = base64ify(proxyUser + ":" + proxyPass)
    request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass

    # 设置IP切换头(根据需求)
    tunnel = random.randint(1, 10000)
    request.headers['Proxy-Tunnel'] = str(tunnel)
    request.headers['User-Agent'] = random.choice(self.USER_AGENT)


class PyppeteerMiddleware(object):
  def __init__(self, **args):
    """
    init logger, loop, browser
    :param args:
    """
    self.logger = getLogger(__name__)
    self.loop = asyncio.get_event_loop()
    self.browser = self.loop.run_until_complete(
      pyppeteer.launch(headless=True))
    self.args = args

  def __del__(self):
    """
    close loop
    :return:
    """
    self.loop.close()

  def render(self, url, retries=1, script=None, wait=0.3, scrolldown=False, sleep=0,
        timeout=8.0, keep_page=False):
    """
    render page with pyppeteer
    :param url: page url
    :param retries: max retry times
    :param script: js script to evaluate
    :param wait: number of seconds to wait before loading the page, preventing timeouts
    :param scrolldown: how many times to page down
    :param sleep: how many long to sleep after initial render
    :param timeout: the longest wait time, otherwise raise timeout error
    :param keep_page: keep page not to be closed, browser object needed
    :param browser: pyppetter browser object
    :param with_result: return with js evaluation result
    :return: content, [result]
    """

    # define async render
    async def async_render(url, script, scrolldown, sleep, wait, timeout, keep_page):
      try:
        # basic render
        page = await self.browser.newPage()
        await asyncio.sleep(wait)
        response = await page.goto(url, options={'timeout': int(timeout * 1000)})
        if response.status != 200:
          return None, None, response.status
        result = None
        # evaluate with script
        if script:
          result = await page.evaluate(script)

        # scroll down for {scrolldown} times
        if scrolldown:
          for _ in range(scrolldown):
            await page._keyboard.down('PageDown')
            await asyncio.sleep(sleep)
        else:
          await asyncio.sleep(sleep)
        if scrolldown:
          await page._keyboard.up('PageDown')

        # get html of page
        content = await page.content()

        return content, result, response.status
      except TimeoutError:
        return None, None, 500
      finally:
        # if keep page, do not close it
        if not keep_page:
          await page.close()

    content, result, status = [None] * 3

    # retry for {retries} times
    for i in range(retries):
      if not content:
        content, result, status = self.loop.run_until_complete(
          async_render(url=url, script=script, sleep=sleep, wait=wait,
                 scrolldown=scrolldown, timeout=timeout, keep_page=keep_page))
      else:
        break

    # if need to return js evaluation result
    return content, result, status

  def process_request(self, request, spider):
    """
    :param request: request object
    :param spider: spider object
    :return: HtmlResponse
    """
    if request.meta.get('render'):
      try:
        self.logger.debug('rendering %s', request.url)
        html, result, status = self.render(request.url)
        return HtmlResponse(url=request.url, body=html, request=request, encoding='utf-8',
                  status=status)
      except websockets.exceptions.ConnectionClosed:
        pass

  @classmethod
  def from_crawler(cls, crawler):
    return cls(**crawler.settings.get('PYPPETEER_ARGS', {}))

然后修改项目配置文件 (./项目名/settings.py)

DOWNLOADER_MIDDLEWARES = {
    'scrapypyppeteer.middlewares.PyppeteerMiddleware': 543,
    'scrapypyppeteer.middlewares.ProxyMiddleware': 100,    
  }

然后我们运行程序

Scrapy框架介绍之Puppeteer渲染的使用

到此这篇关于Scrapy框架介绍之Puppeteer渲染的使用的文章就介绍到这了,更多相关Scrapy Puppeteer渲染内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python使用os模块的os.walk遍历文件夹示例
Jan 27 Python
Python温度转换实例分析
Jan 17 Python
Python使用Selenium+BeautifulSoup爬取淘宝搜索页
Feb 24 Python
解决pycharm无法识别本地site-packages的问题
Oct 13 Python
Python中asyncio模块的深入讲解
Jun 10 Python
OpenCV3.0+Python3.6实现特定颜色的物体追踪
Jul 23 Python
python安装virtualenv虚拟环境步骤图文详解
Sep 18 Python
pymysql 插入数据 转义处理方式
Mar 02 Python
Python3 中sorted() 函数的用法
Mar 24 Python
django的403/404/500错误自定义页面的配置方式
May 21 Python
python中append函数用法讲解
Dec 11 Python
Python 中的函数装饰器和闭包详解
Feb 06 Python
Python内置方法和属性应用:反射和单例(推荐)
Jun 19 #Python
Python应用实现双指数函数及拟合代码实例
Jun 19 #Python
PyQT5 实现快捷键复制表格数据的方法示例
Jun 19 #Python
如何在keras中添加自己的优化器(如adam等)
Jun 19 #Python
详解pyinstaller生成exe的闪退问题解决方案
Jun 19 #Python
Python实现爬取并分析电商评论
Jun 19 #Python
keras 实现轻量级网络ShuffleNet教程
Jun 19 #Python
You might like
php利用iframe实现无刷新文件上传功能的代码
2011/09/29 PHP
ThinkPHP3.2.1图片验证码实现方法
2016/08/19 PHP
php+ajax简单实现全选删除的方法
2016/12/06 PHP
Yii实现微信公众号场景二维码的方法实例
2020/08/30 PHP
jQuery提交表单ajax查询实例代码
2012/10/07 Javascript
JS 对输入框进行限制(常用的都有)
2013/07/30 Javascript
更高效的使用JQuery 这里总结了8个小技巧
2016/04/13 Javascript
DWR3 访问WEB元素的两种方法实例详解
2017/01/03 Javascript
JavaScript中在光标处插入添加文本标签节点的详细方法
2017/03/22 Javascript
ionic中的$ionicPlatform.ready事件中的通用设置
2017/06/11 Javascript
ionic2屏幕适配实现适配手机、平板等设备的示例代码
2017/08/11 Javascript
浅析Visual Studio Code断点调试Vue
2018/02/27 Javascript
js中获取URL参数的共用方法getRequest()方法实例详解
2018/10/24 Javascript
微信小程序实现留言板
2018/10/31 Javascript
Vue传参一箩筐(页面、组件)
2019/04/04 Javascript
nodejs的安装使用与npm的介绍
2019/09/11 NodeJs
浅谈layui 表单元素的选中问题
2019/10/25 Javascript
vue-cli3项目升级到vue-cli4 的方法总结
2020/03/19 Javascript
python中的插值 scipy-interp的实现代码
2018/07/23 Python
TensorFlow Session使用的两种方法小结
2018/07/30 Python
Python中shapefile转换geojson的示例
2019/01/03 Python
Python实现合并excel表格的方法分析
2019/04/13 Python
python实现基于朴素贝叶斯的垃圾分类算法
2019/07/09 Python
python实现12306登录并保存cookie的方法示例
2019/12/17 Python
python3连接MySQL8.0的两种方式
2020/02/17 Python
Python基于pandas绘制散点图矩阵代码实例
2020/06/04 Python
html5 touch事件实现触屏页面上下滑动(一)
2016/03/10 HTML / CSS
机械设计及其自动化求职推荐信
2014/02/17 职场文书
安全生产责任书
2014/03/12 职场文书
服务承诺书怎么写
2014/05/24 职场文书
2014年预备党员群众路线教育实践活动对照检查材料思想汇报
2014/10/02 职场文书
工会2014法制宣传日活动总结
2014/11/01 职场文书
订货会邀请函
2015/01/31 职场文书
上课讲话检讨书范文
2015/05/07 职场文书
2016年小学“感恩教师”主题队日活动总结
2016/04/01 职场文书
Python实现抖音热搜定时爬取功能
2022/03/16 Python