Skip to main content

用于 Scrapy 和 Gerapy 的 Pyppeteer 组件

项目描述

杰拉皮·皮皮特

这是一个在 Scrapy 中支持 pyppeteer 的包,这个包也是 Gerapy 中的一个模块

安装

pip3 install gerapy-pyppeteer

用法

您可以使用PyppeteerRequest指定使用 pyppeteer 呈现的请求。

例如:

yield PyppeteerRequest(detail_url, callback=self.parse_detail)

而且您还需要PyppeteerMiddleware启用DOWNLOADER_MIDDLEWARES

DOWNLOADER_MIDDLEWARES = {
    'gerapy_pyppeteer.downloadermiddlewares.PyppeteerMiddleware': 543,
}

恭喜,您已完成所有必需的配置。

如果您再次运行 Spider,Pyppeteer 将开始渲染您将请求配置为 PyppeteerRequest 的每个网页。

设置

GerapyPyppeteer 提供了一些可选设置。

并发

你可以直接使用 Scrapy 的设置来设置 Pyppeteer 的 Concurrency,例如:

CONCURRENT_REQUESTS = 3

伪装成真正的浏览器

有些网站会检测到 WebDriver 或 Headless,GerapyPyppeteer 可以通过注入脚本来伪装 Chromium。这是默认启用的。

如果网站没有检测到 WebDriver 可以关闭它来加速:

GERAPY_PYPPETEER_PRETEND = False

您也可以使用pretend属性PyppeteerRequest来覆盖此配置。

日志记录级别

默认情况下,Pyppeteer 会记录所有的调试信息,因此 GerapyPyppeteer 将 Pyppeteer 的日志记录级别配置为 WARNING。

如果您想查看更多来自 Pyppeteer 的日志,可以更改此设置:

import logging
GERAPY_PYPPETEER_LOGGING_LEVEL = logging.DEBUG

下载超时

Pyppeteer 可能需要一些时间来呈现所需的网页,您也可以更改此设置,默认为30s

# pyppeteer timeout
GERAPY_PYPPETEER_DOWNLOAD_TIMEOUT = 30

无头

默认情况下,Pyppeteer 运行在Headlessmode 下,您也可以False根据需要将其更改为,默认为True

GERAPY_PYPPETEER_HEADLESS = False

窗口大小

您还可以设置 Pyppeteer 窗口的宽度和高度:

GERAPY_PYPPETEER_WINDOW_WIDTH = 1400
GERAPY_PYPPETEER_WINDOW_HEIGHT = 700

默认值为 1400、700。

Pyppeteer Args

您还可以更改 Pyppeteer 的 args,例如dumpio,devtools等。

可选设置及其默认值:

GERAPY_PYPPETEER_DUMPIO = False
GERAPY_PYPPETEER_DEVTOOLS = False
GERAPY_PYPPETEER_EXECUTABLE_PATH = None
GERAPY_PYPPETEER_DISABLE_EXTENSIONS = True
GERAPY_PYPPETEER_HIDE_SCROLLBARS = True
GERAPY_PYPPETEER_MUTE_AUDIO = True
GERAPY_PYPPETEER_NO_SANDBOX = True
GERAPY_PYPPETEER_DISABLE_SETUID_SANDBOX = True
GERAPY_PYPPETEER_DISABLE_GPU = True

禁用特定资源类型的加载

您可以禁用特定资源类型的加载以减少网页的加载时间。您可以使用以下方式配置禁用的资源类型GERAPY_PYPPETEER_IGNORE_RESOURCE_TYPES

GERAPY_PYPPETEER_IGNORE_RESOURCE_TYPES = []

例如,如果你想禁用 css 和 javascript 的加载,你可以设置如下:

GERAPY_PYPPETEER_IGNORE_RESOURCE_TYPES = ['stylesheet', 'script']

所有可选资源类型列表:

  • 文档:原始 HTML 文档
  • 样式表:CSS 文件
  • 脚本:JavaScript 文件
  • 图片:图片
  • 媒体:媒体文件,例如音频或视频
  • 字体:字体文件
  • texttrack:文本轨道文件
  • xhr: Ajax 请求
  • fetch:获取请求
  • 事件源:事件源
  • 网络套接字:网络套接字
  • manifest:清单文件
  • 其他:其他文件

截屏

您可以获得加载页面的屏幕截图,您可以将screenshotargs 传递给PyppeteerRequest作为 dict:

  • type(str):指定截图类型,可以是jpegpng。默认为png.
  • quality(int):图像的质量,介于 0-100 之间。不适用于png图像。
  • fullPage(bool):当为真时,截取整个可滚动页面的屏幕截图。默认为False.
  • clip(dict):指定页面剪切区域的对象。此选项应具有以下字段:
    • x(int): 剪辑区域左上角的 x 坐标。
    • y(int): 剪辑区域左上角的 y 坐标。
    • width(int): 裁剪区域的宽度。
    • height(int): 裁剪区域的高度。
  • omitBackground(bool):隐藏默认的白色背景并允许以透明方式捕获屏幕截图。
  • encoding(str):图像的编码,可以是base64binary。默认为binary. 如果是二进制,它将返回BytesIO对象。

例如:

yield PyppeteerRequest(start_url, callback=self.parse_index, wait_for='.item .name', screenshot={
            'type': 'png',
            'fullPage': True
        })

然后你可以得到截图结果response.meta['screenshot']

最简单的保存到文件:

def parse_index(self, response):
    with open('screenshot.png', 'wb') as f:
        f.write(response.meta['screenshot'].getbuffer())

如果您想为所有请求启用屏幕截图,您可以通过GERAPY_PYPPETEER_SCREENSHOT.

例如:

GERAPY_PYPPETEER_SCREENSHOT = {
    'type': 'png',
    'fullPage': True
}

PyppeteerRequest

PyppeteerRequest提供可以覆盖上述全局设置的参数。

  • 网址:请求网址
  • 回调:回调
  • “load”、“domcontentloaded”、“networkidle0”、“networkidle2”之一。见https://miyakogi.github.io/pyppeteer/reference.html#pyppeteer.page.Page.goto,默认为domcontentloaded
  • wait_for:等待某个元素加载,也支持dict
  • 脚本:要执行的脚本
  • proxy:这次使用代理,比如http://x.x.x.x:x
  • sleep:加载后的睡眠时间,覆盖GERAPY_PYPPETEER_SLEEP
  • timeout:加载超时,覆盖GERAPY_PYPPETEER_DOWNLOAD_TIMEOUT
  • ignore_resource_types:忽略的资源类型,覆盖GERAPY_PYPPETEER_IGNORE_RESOURCE_TYPES
  • 伪装:伪装成普通浏览器,覆盖GERAPY_PYPPETEER_PRETEND
  • 截图:忽略的资源类型,见 https://miyakogi.github.io/pyppeteer/_modules/pyppeteer/page.html#Page.screenshot,覆盖GERAPY_PYPPETEER_SCREENSHOT

例如,您可以将 PyppeteerRequest 配置为:

from gerapy_pyppeteer import PyppeteerRequest

def parse(self, response):
    yield PyppeteerRequest(url,
        callback=self.parse_detail,
        wait_until='domcontentloaded',
        wait_for='title',
        script='() => { return {name: "Germey"} }',
        sleep=2)

然后 Pyppeteer 将:

  • 等待文件加载
  • 等待标题加载
  • 执行console.log(document)脚本
  • 睡2s
  • 返回渲染的网页内容,获取自response.meta['screenshot']
  • 返回脚本执行结果,获取自response.meta['script_result']

对于 JavaScript 控制的等待机制,可以使用 await in script,例如:

js = '''async () => {
    await new Promise(resolve => setTimeout(resolve, 10000));
    return {
        'name': 'Germey'
    }
}
'''
yield PyppeteerRequest(url, callback=self.parse, script=js)

然后你可以得到脚本结果response.meta['script_result'],结果是{'name': 'Germey'}

如果您认为 JavaScript 是有线编写的,您可以使用 actions 参数来定义一个函数来执行Python基于函数的函数,例如:

async def execute_actions(page: Page):
    await page.evaluate('() => { document.title = "Hello World"; }')
    return 1
yield PyppeteerRequest(url, callback=self.parse, actions=execute_actions)

然后你可以得到动作结果response.meta['actions_result'],结果是1

例子

有关详细信息,请参阅示例

您也可以直接使用 Docker 运行:

docker run germey/gerapy-pyppeteer-example

输出:

2020-07-13 01:49:13 [scrapy.utils.log] INFO: Scrapy 2.2.0 started (bot: example)
2020-07-13 01:49:13 [scrapy.utils.log] INFO: Versions: lxml 4.3.3.0, libxml2 2.9.9, cssselect 1.1.0, parsel 1.6.0, w3lib 1.22.0, Twisted 20.3.0, Python 3.7.7 (default, May  6 2020, 04:59:01) - [Clang 4.0.1 (tags/RELEASE_401/final)], pyOpenSSL 19.1.0 (OpenSSL 1.1.1d  10 Sep 2019), cryptography 2.8, Platform Darwin-19.4.0-x86_64-i386-64bit
2020-07-13 01:49:13 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor
2020-07-13 01:49:13 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'example',
 'CONCURRENT_REQUESTS': 3,
 'NEWSPIDER_MODULE': 'example.spiders',
 'RETRY_HTTP_CODES': [403, 500, 502, 503, 504],
 'SPIDER_MODULES': ['example.spiders']}
2020-07-13 01:49:13 [scrapy.extensions.telnet] INFO: Telnet Password: 83c276fb41754bd0
2020-07-13 01:49:13 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2020-07-13 01:49:13 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'gerapy_pyppeteer.downloadermiddlewares.PyppeteerMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2020-07-13 01:49:13 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2020-07-13 01:49:13 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2020-07-13 01:49:13 [scrapy.core.engine] INFO: Spider opened
2020-07-13 01:49:13 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-07-13 01:49:13 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2020-07-13 01:49:13 [example.spiders.book] INFO: crawling https://dynamic5.scrape.center/page/1
2020-07-13 01:49:13 [gerapy.pyppeteer] DEBUG: processing request <GET https://dynamic5.scrape.center/page/1>
2020-07-13 01:49:13 [gerapy.pyppeteer] DEBUG: set options {'headless': True, 'dumpio': False, 'devtools': False, 'args': ['--window-size=1400,700', '--disable-extensions', '--hide-scrollbars', '--mute-audio', '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']}
2020-07-13 01:49:14 [gerapy.pyppeteer] DEBUG: crawling https://dynamic5.scrape.center/page/1
2020-07-13 01:49:19 [gerapy.pyppeteer] DEBUG: waiting for .item .name finished
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: wait for .item .name finished
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: close pyppeteer
2020-07-13 01:49:20 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://dynamic5.scrape.center/page/1> (referer: None)
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: processing request <GET https://dynamic5.scrape.center/detail/26898909>
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: processing request <GET https://dynamic5.scrape.center/detail/26861389>
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: processing request <GET https://dynamic5.scrape.center/detail/26855315>
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: set options {'headless': True, 'dumpio': False, 'devtools': False, 'args': ['--window-size=1400,700', '--disable-extensions', '--hide-scrollbars', '--mute-audio', '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']}
2020-07-13 01:49:20 [gerapy.pyppeteer] DEBUG: set options {'headless': True, 'dumpio': False, 'devtools': False, 'args': ['--window-size=1400,700', '--disable-extensions', '--hide-scrollbars', '--mute-audio', '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']}
2020-07-13 01:49:21 [gerapy.pyppeteer] DEBUG: set options {'headless': True, 'dumpio': False, 'devtools': False, 'args': ['--window-size=1400,700', '--disable-extensions', '--hide-scrollbars', '--mute-audio', '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']}
2020-07-13 01:49:21 [gerapy.pyppeteer] DEBUG: crawling https://dynamic5.scrape.center/detail/26855315
2020-07-13 01:49:21 [gerapy.pyppeteer] DEBUG: crawling https://dynamic5.scrape.center/detail/26861389
2020-07-13 01:49:21 [gerapy.pyppeteer] DEBUG: crawling https://dynamic5.scrape.center/detail/26898909
2020-07-13 01:49:24 [gerapy.pyppeteer] DEBUG: waiting for .item .name finished
2020-07-13 01:49:24 [gerapy.pyppeteer] DEBUG: wait for .item .name finished
2020-07-13 01:49:24 [gerapy.pyppeteer] DEBUG: close pyppeteer
2020-07-13 01:49:24 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://dynamic5.scrape.center/detail/26861389> (referer: https://dynamic5.scrape.center/page/1)
2020-07-13 01:49:24 [gerapy.pyppeteer] DEBUG: processing request <GET https://dynamic5.scrape.center/page/2>
2020-07-13 01:49:24 [gerapy.pyppeteer] DEBUG: set options {'headless': True, 'dumpio': False, 'devtools': False, 'args': ['--window-size=1400,700', '--disable-extensions', '--hide-scrollbars', '--mute-audio', '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']}
2020-07-13 01:49:25 [scrapy.core.scraper] DEBUG: Scraped from <200 https://dynamic5.scrape.center/detail/26861389>
{'name': '壁穴ヘブンホール',
 'score': '5.6',
 'tags': ['BL漫画', '小基漫', 'BL', '『又腐又基』', 'BLコミック']}
2020-07-13 01:49:25 [gerapy.pyppeteer] DEBUG: waiting for .item .name finished
2020-07-13 01:49:25 [gerapy.pyppeteer] DEBUG: crawling https://dynamic5.scrape.center/page/2
2020-07-13 01:49:26 [gerapy.pyppeteer] DEBUG: wait for .item .name finished
2020-07-13 01:49:26 [gerapy.pyppeteer] DEBUG: close pyppeteer
2020-07-13 01:49:26 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://dynamic5.scrape.center/detail/26855315> (referer: https://dynamic5.scrape.center/page/1)
2020-07-13 01:49:26 [gerapy.pyppeteer] DEBUG: processing request <GET https://dynamic5.scrape.center/detail/27047626>
2020-07-13 01:49:26 [gerapy.pyppeteer] DEBUG: set options {'headless': True, 'dumpio': False, 'devtools': False, 'args': ['--window-size=1400,700', '--disable-extensions', '--hide-scrollbars', '--mute-audio', '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']}
2020-07-13 01:49:26 [scrapy.core.scraper] DEBUG: Scraped from <200 https://dynamic5.scrape.center/detail/26855315>
{'name': '冒险小虎队', 'score': '9.4', 'tags': ['冒险小虎队', '童年', '冒险', '推理', '小时候读的']}
2020-07-13 01:49:26 [gerapy.pyppeteer] DEBUG: waiting for .item .name finished
2020-07-13 01:49:26 [gerapy.pyppeteer] DEBUG: crawling https://dynamic5.scrape.center/detail/27047626
2020-07-13 01:49:27 [gerapy.pyppeteer] DEBUG: wait for .item .name finished
2020-07-13 01:49:27 [gerapy.pyppeteer] DEBUG: close pyppeteer
...

故障排除

Pyppeteer 无法正常启动

Chromium 下载速度太慢,无法正常使用。

这里有两个解决方案:

解决方案 1(推荐)

pyppeteer/chromium_downloader.py在第 22 行修改驱动下载源:

# Default:
DEFAULT_DOWNLOAD_HOST = 'https://storage.googleapis.com'
# modify
DEFAULT_DOWNLOAD_HOST = http://npm.taobao.org/mirror

解决方案 2

pyppeteer/chromium_downloader.py在第 45 行修改驱动执行路径:

# Default:
chromiumExecutable = {
    'linux': DOWNLOADS_FOLDER / REVISION / 'chrome-linux' / 'chrome',
    'mac': (DOWNLOADS_FOLDER / REVISION / 'chrome-mac' / 'Chromium.app' /
            'Contents' / 'MacOS' / 'Chromium'),
    'win32': DOWNLOADS_FOLDER / REVISION / windowsArchive / 'chrome.exe',
    'win64': DOWNLOADS_FOLDER / REVISION / windowsArchive / 'chrome.exe',
}

您可以找到自己的操作系统,修改您的 chrome 或 chrome 可执行路径。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

scrapyer-gerapy-pyppeteer-0.1.4.tar.gz (33.2 kB 查看哈希)

已上传 source