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文件读写操作与linux shell变量命令交互执行的方法
Jan 14 Python
使用pygame模块编写贪吃蛇的实例讲解
Feb 05 Python
python中使用iterrows()对dataframe进行遍历的实例
Jun 09 Python
python获取服务器响应cookie的实例
Dec 28 Python
python实现连连看辅助(图像识别)
Mar 25 Python
wxPython实现分隔窗口
Nov 19 Python
Flask框架搭建虚拟环境的步骤分析
Dec 21 Python
PyCharm如何导入python项目的方法
Feb 06 Python
python 抓取知乎指定回答下视频的方法
Jul 09 Python
Python3爬虫中关于中文分词的详解
Jul 29 Python
matplotlib交互式数据光标实现(mplcursors)
Jan 13 Python
Django框架中表单的用法
Jun 10 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
《一拳超人》埼玉一拳下去,他们存在了800年毫无意义!
2020/03/02 日漫
php使用MySQL保存session会话的方法
2015/06/18 PHP
PHP框架自动加载类文件原理详解
2017/06/06 PHP
PHP编程文件处理类SplFileObject和SplFileInfo用法实例分析
2017/07/22 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
2017/11/14 PHP
php中pcntl_fork创建子进程的方法实例
2019/03/14 PHP
小议javascript 设计模式 推荐
2009/10/28 Javascript
javascript实现的像java、c#之类的sleep暂停的函数代码
2010/03/04 Javascript
Jquery中给animation加更多的运作效果实例
2013/09/05 Javascript
Javascript中浮点数相乘的一个解决方法
2014/06/03 Javascript
JavaScript定时器和优化的取消定时器方法
2015/07/03 Javascript
详解JS中Array对象扩展与String对象扩展
2016/01/07 Javascript
js点击按钮实现水波纹效果代码(CSS3和Canves)
2016/09/15 Javascript
JS中图片压缩的方法小结
2017/11/14 Javascript
express如何使用session与cookie的方法
2018/01/30 Javascript
去掉vue 中的代码规范检测两种方法(Eslint验证)
2018/03/21 Javascript
vuex实现的简单购物车功能示例
2019/02/13 Javascript
[02:19]DOTA选手解说齐贺岁
2018/02/11 DOTA
[01:04:48]VGJ.S vs TNC Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
[35:39]完美世界DOTA2联赛PWL S2 FTD.C vs Rebirth 第二场 11.22
2020/11/24 DOTA
python回调函数用法实例分析
2015/05/09 Python
python中yaml配置文件模块的使用详解
2018/04/27 Python
pygame游戏之旅 添加游戏暂停功能
2018/11/21 Python
opencv python统计及绘制直方图的方法
2019/01/21 Python
python实现烟花小程序
2019/01/30 Python
python实现连连看游戏
2020/02/14 Python
python thrift 实现 单端口多服务的过程
2020/06/08 Python
美国体育用品商店:Paragon Sports
2017/10/08 全球购物
什么是Assembly(程序集)
2014/09/14 面试题
公司董事长职责
2013/12/12 职场文书
酒店优秀员工事迹材料
2014/06/02 职场文书
铣床操作工岗位职责
2014/06/13 职场文书
汽修专业自荐信
2014/07/07 职场文书
党的群众路线对照检查材料(个人)
2014/09/24 职场文书
工作证明英文模板
2014/10/21 职场文书
吴仁宝观后感
2015/06/09 职场文书