需求分析

今天,一个正在学习爬虫的小伙伴找到我说,“仙草哥哥,我在b站上看到了一个up主,教学了一段代码,可以通过js实现自动点击,但是呢,我感觉这个自动点击一点都不方便。“

我感到很奇怪,问他,“为什么自动点击会不方便呢?”

他说,“这个自动点击是很不错,但是首先需要手动打开浏览器,然后才能在控制台中运行js代码。我都要使用自动点击功能了,还需要手动复制代码,这太不好了。仙草哥哥,你能不能教教我,怎么才可以真正实现自动运行呢?”

好吧,这个问题没什么难的,也就是说,一个js能够实现的点击功能,如何通过python的爬虫实现呢?下面就来看看吧

js自动点击

首先,我们还是学习一下别人up主的实现,看看他是如何通过js完成自动点击的

// 第一步,通过open函数,打开一个新的页面
// 这一步的关键点在于要选择一个合适的浏览器,以及不能跨域访问
var a = open(url);

// 第二步,找到所需元素,并完成点击
a.document.getElementById("j-top-vote").click();

很简单的一段js代码,也就是打开并点击,然后呢,这位up主还把这个过程,写成了一个定时器

// 通过定时器完成打开并且点击
var a = open(url);
setTimeout(x => {
a.document.getElementById("j-top-vote").click();
}, 2000);

不过就如同之前小伙伴所说的那样,由于这一段是js的代码,需要打开浏览器以后手动运行不是特别的方便,无法实现全自动

selenium实现

如果这样一个点击功能,是使用传统的selenium去执行的话,应该怎么做呢?

其实,还是一样的,都是打开浏览器,访问页面,找到元素,最后点击。比如说运行一下的代码可以完成这样一个功能

import time
from selenium import webdriver
from base64 import b64decode

driver = webdriver.Chrome()
url = b64decode("aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTYlOUQlOEUlRTYlQjglQjgvMjM2ODczNDU=").decode()
driver.get(url)
driver.find_element("id", "j-top-vote").click()
time.sleep(1)

driver.quit()

虽然说实现起来也很容易,没遇到什么困难,但是这样做并不好。主要的原因在于,既然“前人”已经帮我们把js的代码写完了,那我们就应该利用上,不应该自己重新写一份,也就是说,我们完全可以通过selenium打开的浏览器,去执行之前现成的js代码,这样就可以避免自己从头开始,另起炉灶了。如下所示

import time
from selenium import webdriver
from base64 import b64decode

driver = webdriver.Chrome()
url = b64decode("aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTYlOUQlOEUlRTYlQjglQjgvMjM2ODczNDU=").decode()
driver.get(url)

js = """
var a = open("%s");
setTimeout(x => {
a.document.getElementById("j-top-vote").click();
}, 2000);
""" % url

driver.execute_script(js)
time.sleep(3)
driver.quit()

可以看到,这样写程序就不需要自己重新写了,完全可以把别人写好的js代码直接拿来使用,非常的方便啊

其他实现方法

有的小伙伴看到这里,可能会有一个疑问,为什么每次都是selenium呢?难道说python就只能靠selenium来实现这样的功能吗?

当然不是了,事实上,方法是很多的,只不过通过selenium实现的方法比较简单易用,很常见而已,比如说,我们可以通过splash重新实现一下这个相同的功能,在splash中同样也可以执行js代码,所以我们完全可以用上之前的代码

import requests
from urllib.parse import quote
from base64 import b64decode

url = b64decode("aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTYlOUQlOEUlRTYlQjglQjgvMjM2ODczNDU=").decode()
lua = """
function main(splash)
    splash.resource_timeout = 10
    splash:go("%s")
    splash:wait(1)
    local js = "setTimeout(x=>{document.getElementById('j-top-vote').click();}, 2000);"
    splash:evaljs(js)
    splash:wait(3)
    local count = splash:evaljs("document.getElementsByClassName('vote-count')[0].innerHTML;")
    return count
end
""" % url

url = "http://localhost:8050/execute?lua_source=" + quote(lua)
r = requests.get(url)
print("当前的点击:", r.text)

顺便一提,以上的代码的前提是,你已经在本机运行了splash,并且使用了默认的8050端口。如果你在本机没有运行splash,或者端口不是8050,需要对程序作出相应的调整哦!

可以看到,使用splash的程序代码字数可能是稍微多了一点,但是也很好的完成了任务,可喜可贺,可喜可贺


当然啦,这个自动点击功能并非只能用在这一个页面上,它当然也可以用于和这个页面相似的其他页面上,这个可以根据你自己的需要,进行简单的调整