Scrapy-Splash 等待页面加载
Scrapy-Splash Waiting for Page to Load
我是 scrapy 和 splash 的新手,我需要从单页和常规网络应用程序中抓取数据。
不过,需要注意的是,我主要是从内部工具和应用程序中抓取数据,因此有些需要身份验证,并且所有这些都需要至少几秒钟的加载时间才能完全加载页面。
我天真地尝试了 Python time.sleep(seconds) 但它没有用。基本上,似乎 SplashRequest 和 scrapy.Request 都 运行 和 yield 结果。然后我了解了 LUA 脚本作为这些请求的参数,并尝试使用各种形式的 wait() 的 LUA 脚本,但看起来这些请求实际上从未 运行 [=38] =] 脚本。它立即完成,我的 HTMl 选择器没有找到我要找的任何东西。
我正在按照此处 https://github.com/scrapy-plugins/scrapy-splash 的指示进行操作,并在 localhost:8050 上安装了他们的 docker 实例 运行 并创建了一个 settings.py。
有经验的人知道我可能遗漏了什么吗?
谢谢!
spider.py
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy_splash import SplashRequest
import logging
import base64
import time
# from selenium import webdriver
# lua_script="""
# function main(splash)
# splash:set_user_agent(splash.args.ua)
# assert(splash:go(splash.args.url))
# splash:wait(5)
# -- requires Splash 2.3
# -- while not splash:select('#user-form') do
# -- splash:wait(5)
# -- end
# repeat
# splash:wait(5))
# until( splash:select('#user-form') ~= nil )
# return {html=splash:html()}
# end
# """
load_page_script="""
function main(splash)
splash:set_user_agent(splash.args.ua)
assert(splash:go(splash.args.url))
splash:wait(5)
function wait_for(splash, condition)
while not condition() do
splash:wait(0.5)
end
end
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.resume();
}, 5000);
}
]])
wait_for(splash, function()
return splash:evaljs("document.querySelector('#user-form') != null")
end)
-- repeat
-- splash:wait(5))
-- until( splash:select('#user-form') ~= nil )
return {html=splash:html()}
end
"""
class HelpSpider(scrapy.Spider):
name = "help"
allowed_domains = ["secet_internal_url.com"]
start_urls = ['https://secet_internal_url.com']
# http_user = 'splash-user'
# http_pass = 'splash-password'
def start_requests(self):
logger = logging.getLogger()
login_page = 'https://secet_internal_url.com/#/auth'
splash_args = {
'html': 1,
'png': 1,
'width': 600,
'render_all': 1,
'lua_source': load_page_script
}
#splash_args = {
# 'html': 1,
# 'png': 1,
# 'width': 600,
# 'render_all': 1,
# 'lua_source': lua_script
#}
yield SplashRequest(login_page, self.parse, endpoint='execute', magic_response=True, args=splash_args)
def parse(self, response):
# time.sleep(10)
logger = logging.getLogger()
html = response._body.decode("utf-8")
# Looking for a form with the ID 'user-form'
form = response.css('#user-form')
logger.info("####################")
logger.info(form)
logger.info("####################")
我想通了!
简答
我的 Spider class 配置不正确,无法将 splash 与 scrapy 一起使用。
长答案
运行ning splash with scrape 的一部分,在我的例子中,运行ning 一个本地 Docker 实例,它用于将我的请求加载到 运行 Lua 脚本中。需要注意的一个重要警告是 github 页面中描述的启动设置必须是蜘蛛 class 本身 的 属性,所以我将此代码添加到我的 Spider:
custom_settings = {
'SPLASH_URL': 'http://localhost:8050',
# if installed Docker Toolbox:
# 'SPLASH_URL': 'http://192.168.99.100:8050',
'DOWNLOADER_MIDDLEWARES': {
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
},
'SPIDER_MIDDLEWARES': {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
},
'DUPEFILTER_CLASS': 'scrapy_splash.SplashAwareDupeFilter',
}
然后我注意到我的 Lua 代码 运行ning,以及 Docker 容器日志指示交互。在使用 splash:select() 修复错误后,我的登录脚本工作正常,我的等待也是如此:
splash:wait( seconds_to_wait )
最后,我创建了一个 Lua 脚本来处理登录、重定向和从页面收集 link 和文本。我的应用程序是一个 AngularJS 应用程序,因此我无法收集 link 或访问它们,除非单击。这个脚本让我 运行 浏览每个 link,点击它,收集内容。
我想另一种解决方案是使用端到端测试工具,例如 Selenium/WebDriver 或 Cypress,但我更喜欢使用 scrapy 进行抓取和测试工具进行测试。我想每个人都有自己的(Python 或 NodeJS 工具)。
妙招
另一件对调试非常有帮助的事情是,当你运行为 Scrapy-Splash 设置 Docker 实例时,你可以在浏览器中访问 URL还有一个交互式“请求测试器”,可以让您测试 Lua 脚本并查看呈现的 HTML 结果(例如,验证登录或页面访问)。对我来说,这个 url 是 http://0.0.0.0:8050,而这个 URL 是在你的设置中设置的,应该配置成与你的 Docker容器。
干杯!
我是 scrapy 和 splash 的新手,我需要从单页和常规网络应用程序中抓取数据。
不过,需要注意的是,我主要是从内部工具和应用程序中抓取数据,因此有些需要身份验证,并且所有这些都需要至少几秒钟的加载时间才能完全加载页面。
我天真地尝试了 Python time.sleep(seconds) 但它没有用。基本上,似乎 SplashRequest 和 scrapy.Request 都 运行 和 yield 结果。然后我了解了 LUA 脚本作为这些请求的参数,并尝试使用各种形式的 wait() 的 LUA 脚本,但看起来这些请求实际上从未 运行 [=38] =] 脚本。它立即完成,我的 HTMl 选择器没有找到我要找的任何东西。
我正在按照此处 https://github.com/scrapy-plugins/scrapy-splash 的指示进行操作,并在 localhost:8050 上安装了他们的 docker 实例 运行 并创建了一个 settings.py。
有经验的人知道我可能遗漏了什么吗?
谢谢!
spider.py
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy_splash import SplashRequest
import logging
import base64
import time
# from selenium import webdriver
# lua_script="""
# function main(splash)
# splash:set_user_agent(splash.args.ua)
# assert(splash:go(splash.args.url))
# splash:wait(5)
# -- requires Splash 2.3
# -- while not splash:select('#user-form') do
# -- splash:wait(5)
# -- end
# repeat
# splash:wait(5))
# until( splash:select('#user-form') ~= nil )
# return {html=splash:html()}
# end
# """
load_page_script="""
function main(splash)
splash:set_user_agent(splash.args.ua)
assert(splash:go(splash.args.url))
splash:wait(5)
function wait_for(splash, condition)
while not condition() do
splash:wait(0.5)
end
end
local result, error = splash:wait_for_resume([[
function main(splash) {
setTimeout(function () {
splash.resume();
}, 5000);
}
]])
wait_for(splash, function()
return splash:evaljs("document.querySelector('#user-form') != null")
end)
-- repeat
-- splash:wait(5))
-- until( splash:select('#user-form') ~= nil )
return {html=splash:html()}
end
"""
class HelpSpider(scrapy.Spider):
name = "help"
allowed_domains = ["secet_internal_url.com"]
start_urls = ['https://secet_internal_url.com']
# http_user = 'splash-user'
# http_pass = 'splash-password'
def start_requests(self):
logger = logging.getLogger()
login_page = 'https://secet_internal_url.com/#/auth'
splash_args = {
'html': 1,
'png': 1,
'width': 600,
'render_all': 1,
'lua_source': load_page_script
}
#splash_args = {
# 'html': 1,
# 'png': 1,
# 'width': 600,
# 'render_all': 1,
# 'lua_source': lua_script
#}
yield SplashRequest(login_page, self.parse, endpoint='execute', magic_response=True, args=splash_args)
def parse(self, response):
# time.sleep(10)
logger = logging.getLogger()
html = response._body.decode("utf-8")
# Looking for a form with the ID 'user-form'
form = response.css('#user-form')
logger.info("####################")
logger.info(form)
logger.info("####################")
我想通了!
简答
我的 Spider class 配置不正确,无法将 splash 与 scrapy 一起使用。
长答案
运行ning splash with scrape 的一部分,在我的例子中,运行ning 一个本地 Docker 实例,它用于将我的请求加载到 运行 Lua 脚本中。需要注意的一个重要警告是 github 页面中描述的启动设置必须是蜘蛛 class 本身 的 属性,所以我将此代码添加到我的 Spider:
custom_settings = {
'SPLASH_URL': 'http://localhost:8050',
# if installed Docker Toolbox:
# 'SPLASH_URL': 'http://192.168.99.100:8050',
'DOWNLOADER_MIDDLEWARES': {
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
},
'SPIDER_MIDDLEWARES': {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
},
'DUPEFILTER_CLASS': 'scrapy_splash.SplashAwareDupeFilter',
}
然后我注意到我的 Lua 代码 运行ning,以及 Docker 容器日志指示交互。在使用 splash:select() 修复错误后,我的登录脚本工作正常,我的等待也是如此:
splash:wait( seconds_to_wait )
最后,我创建了一个 Lua 脚本来处理登录、重定向和从页面收集 link 和文本。我的应用程序是一个 AngularJS 应用程序,因此我无法收集 link 或访问它们,除非单击。这个脚本让我 运行 浏览每个 link,点击它,收集内容。
我想另一种解决方案是使用端到端测试工具,例如 Selenium/WebDriver 或 Cypress,但我更喜欢使用 scrapy 进行抓取和测试工具进行测试。我想每个人都有自己的(Python 或 NodeJS 工具)。
妙招
另一件对调试非常有帮助的事情是,当你运行为 Scrapy-Splash 设置 Docker 实例时,你可以在浏览器中访问 URL还有一个交互式“请求测试器”,可以让您测试 Lua 脚本并查看呈现的 HTML 结果(例如,验证登录或页面访问)。对我来说,这个 url 是 http://0.0.0.0:8050,而这个 URL 是在你的设置中设置的,应该配置成与你的 Docker容器。
干杯!