Scrapy Splash 点击按钮不起作用
Scrapy Splash click button doesn't work
我想做什么
在 avito.ru(俄罗斯房地产网站)上,某人的 phone 在您单击它之前是隐藏的。我想用 Scrapy+Splash 收集 phone.
示例 URL:https://www.avito.ru/moskva/kvartiry/2-k_kvartira_84_m_412_et._992361048
点击按钮后弹出,可见phone
我正在使用 Splash execute API 和以下 Lua 脚本:
function main(splash)
splash:go(splash.args.url)
splash:wait(10)
splash:runjs("document.getElementsByClassName('item-phone-button')[0].click()")
splash:wait(10)
return splash:png()
end
问题
按钮没有被点击,phone号码没有显示。这是一项微不足道的任务,我无法解释为什么它不起作用。
如果我们将 item-phone-button
替换为 js-show-stat
,则同一页面上的另一个字段的点击效果很好。所以 Javascript 一般 是可以的,蓝色的 "Display phone" 按钮一定很特别。
我试过的
为了隔离问题,我用最少的示例脚本创建了一个回购协议,并为 Splash 创建了一个 docker-compose 文件:https://github.com/alexanderlukanin13/splash-avito-phone
Javascript 代码有效,您可以在 Chrome 和 Firefox
中使用 Javascript 控制台验证它
document.getElementsByClassName('item-phone-button')[0].click()
我已经用 Splash 版本 3.0、3.1、3.2 试过了,结果是一样的。
更新
我也试过:
@Lore 的建议,包括 simulateClick()
方法(参见 simulate_click 分支)
mouseDown/mouseUp 此处描述的事件:Simulating a mousedown, click, mouseup sequence in Tampermonkey? (see trigger_mouse_event branch)
我不知道你的实现是如何工作的,但我建议将 main
重命名为 parse
,蜘蛛程序在启动时调用的默认函数。
如果这不是问题,首先要做的是控制是否使用 Javascript 和 css 选择器选择了 class 的正确元素。也许它存在另一个具有 item-phone-button
class 属性的项目,而您点击了错误的位置。
如果以上都正确,我建议两个对我有用的选项:
Using Splash mouse_click and Splash wait(后者我看你已经用过了)。如果它不起作用,请尝试双击,替换为您的代码:
local button = splash:select('item phone-button')
button:mouse_click()
button:mouse_click()
使用 Splash wait_for_resume,执行 javascript 代码直到终止,然后重新启动 LUA。您的代码也会变得更简单:
function main(splash)
splash:go(splash.args.url)
splash:wait_for_resume("document.getElementsByClassName([[
function main(splash) {
document.getElementsByClassName('item-phone-button');[0].click()
splash.resume();
}
]])
return splash:png()
end
编辑:使用 dispatchEvent
代替 click()
似乎很好,就像 this example:
function simulateClick() {
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// A handler called preventDefault.
alert("cancelled");
} else {
// None of the handlers called preventDefault.
alert("not cancelled");
}
}
以下脚本适合我:
function main(splash, args)
splash.private_mode_enabled = false
assert(splash:go(args.url))
btn = splash:select_all('.item-phone-button')[2]
btn:mouse_click()
btn.style.border = "5px solid black"
assert(splash:wait(0.5))
return {
num = #splash:select_all('.item-phone-button'),
html = splash:html(),
png = splash:png(),
har = splash:har(),
}
end
原始解决方案存在 2 个问题:
- 有 2 个元素 'item-phone-button' class,感兴趣的按钮是第二个。我已经通过设置
btn.style.border = "5px solid black"
检查了哪个元素匹配。
- 此网站需要禁用隐私模式,可能是因为它使用了 localStorage。检查 http://splash.readthedocs.io/en/stable/faq.html#website-is-not-rendered-correctly 以获取其他常见建议。
我想做什么
在 avito.ru(俄罗斯房地产网站)上,某人的 phone 在您单击它之前是隐藏的。我想用 Scrapy+Splash 收集 phone.
示例 URL:https://www.avito.ru/moskva/kvartiry/2-k_kvartira_84_m_412_et._992361048
点击按钮后弹出,可见phone
我正在使用 Splash execute API 和以下 Lua 脚本:
function main(splash)
splash:go(splash.args.url)
splash:wait(10)
splash:runjs("document.getElementsByClassName('item-phone-button')[0].click()")
splash:wait(10)
return splash:png()
end
问题
按钮没有被点击,phone号码没有显示。这是一项微不足道的任务,我无法解释为什么它不起作用。
如果我们将 item-phone-button
替换为 js-show-stat
,则同一页面上的另一个字段的点击效果很好。所以 Javascript 一般 是可以的,蓝色的 "Display phone" 按钮一定很特别。
我试过的
为了隔离问题,我用最少的示例脚本创建了一个回购协议,并为 Splash 创建了一个 docker-compose 文件:https://github.com/alexanderlukanin13/splash-avito-phone
Javascript 代码有效,您可以在 Chrome 和 Firefox
中使用 Javascript 控制台验证它document.getElementsByClassName('item-phone-button')[0].click()
我已经用 Splash 版本 3.0、3.1、3.2 试过了,结果是一样的。
更新
我也试过:
@Lore 的建议,包括
simulateClick()
方法(参见 simulate_click 分支)mouseDown/mouseUp 此处描述的事件:Simulating a mousedown, click, mouseup sequence in Tampermonkey? (see trigger_mouse_event branch)
我不知道你的实现是如何工作的,但我建议将 main
重命名为 parse
,蜘蛛程序在启动时调用的默认函数。
如果这不是问题,首先要做的是控制是否使用 Javascript 和 css 选择器选择了 class 的正确元素。也许它存在另一个具有 item-phone-button
class 属性的项目,而您点击了错误的位置。
如果以上都正确,我建议两个对我有用的选项:
local button = splash:select('item phone-button')
button:mouse_click()
button:mouse_click()
function main(splash)
splash:go(splash.args.url)
splash:wait_for_resume("document.getElementsByClassName([[
function main(splash) {
document.getElementsByClassName('item-phone-button');[0].click()
splash.resume();
}
]])
return splash:png()
end
编辑:使用 dispatchEvent
代替 click()
似乎很好,就像 this example:
function simulateClick() {
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// A handler called preventDefault.
alert("cancelled");
} else {
// None of the handlers called preventDefault.
alert("not cancelled");
}
}
以下脚本适合我:
function main(splash, args)
splash.private_mode_enabled = false
assert(splash:go(args.url))
btn = splash:select_all('.item-phone-button')[2]
btn:mouse_click()
btn.style.border = "5px solid black"
assert(splash:wait(0.5))
return {
num = #splash:select_all('.item-phone-button'),
html = splash:html(),
png = splash:png(),
har = splash:har(),
}
end
原始解决方案存在 2 个问题:
- 有 2 个元素 'item-phone-button' class,感兴趣的按钮是第二个。我已经通过设置
btn.style.border = "5px solid black"
检查了哪个元素匹配。 - 此网站需要禁用隐私模式,可能是因为它使用了 localStorage。检查 http://splash.readthedocs.io/en/stable/faq.html#website-is-not-rendered-correctly 以获取其他常见建议。