腾讯DeepOcean原创文章:
在“爬虫的攻守之道(一)”中你可能已经了解到了无头浏览器的作用以及使用的方法,那么本篇文章就让我们一起用无头浏览器做点事情。是的你没有看错,我们要“搞”的对象就是百度指数这个网站,不知道你平时是否会应用到这里面的数据呢?
今天的主要目标就是使用无头浏览器登录百度指数网站,并且绕开它的人机验证,不知道你发现没有,当我们人为正常登录这个网站的时候就不会出现字母、数字或者汉字验证码,而使用无头浏览器登录的时候就会出现这些验证码,闲言少叙我们直接开始正题。
一 正常人为登录为什么不出现验证码?
我们在使用浏览器正常登录百度指数网站的时候发现一般不会弹出验证码的提示。但是如果你使用无头浏览器去登录的时候就会出现验证码,那么这两者登录的区别在哪里呢?
经过我不断的验证发现了两个问题,当我们使用无头浏览器登录的时候做一些类似于人类的操作,例如在窗口中滑动鼠标,或者改变窗口的大小,这样百度指数网站就会认为你是人为的在操作。
第二个问题就是在我们使用无头浏览器输入账号和密码的时候,我们在手动输入密码的时候或多或少的在输入字符之间都会存在时间间隔,而使用无头浏览器的时候程序会零间隔的输入,这样百度指数网站就会认为你是一个程序在输入了。
二 python无头浏览器准备
from selenium import webdriverfrom selenium.webdriver.common.action_chains import ActionChainsimport timeimport sys复制代码
word = sys.argv[1] phone = '此处是你登录百度指数网站的用户名' password = '此处是你登录百度指数网站的密码' 复制代码
在上面的代码中我们引入了一些python的库,接下来就是使用无头浏览器前的准备工作。
#打开chrome无头浏览器opt = webdriver.ChromeOptions()opt.set_headless()driver = webdriver.Chrome(options=opt)executor_url = driver.command_executor._urlsession_id = driver.session_id
#将打开的浏览区url和session_id存储起来,提供给下一次应用 file = open('browserMsg.txt','w') file.writelines([executor_url, 'n',session_id]) file.close()
复制代码
driver.implicitly_wait(20) driver.set_window_size(1000, 800) driver.get(""+ word +"?words="+ word) 复制代码
在上面的代码中我们使用webdriver的内置函数初始化了无头浏览器,你可能发现我使用了executor_url和session_id变量存储了点东西,没错,我将此次打开的浏览器信息(url和sessionId)存储在了一个txt文件中,这样下次我再使用百度指数的时候只需要使用python连接上这个被存储信息的无头浏览器进程,那么就可以节省掉重复登录所带来的风险了,并且还能节省进程数目(此处如果你不需要的话,无需关注)。
接下来我们隐式等待了20秒,并且将无头浏览器的窗口设置为了宽1000高800(你可以改变数值),最后我们打开了百度指数的网站,并且链接中带有我们想要查询的词。
三 进军
time.sleep(1)driver.set_window_size(1200, 800)time.sleep(1)driver.set_window_size(1000, 800)time.sleep(2)复制代码
上面代码的作用是先将无头浏览器窗口的宽变为1200,然后再变为1000,为了使得此处的操作更像人为操作,我加了一些延时效果,接下来就是输入密码的环节了。
getUserPhoneDom = driver.find_element_by_id('TANGRAM__PSP_4__userName')getUserPassDom = driver.find_element_by_id('TANGRAM__PSP_4__password')复制代码
for i in phone: getUserPhoneDom.send_keys(i) time.sleep(.4) for j in password: getUserPassDom.send_keys(j) time.sleep(.4) 复制代码
在上面的代码中我先使用了getUserPhoneDom 变量存储了需要输入用户名的输入框信息,使用getUserPassDom 变量存储了需要输入密码的输入框信息,然后使用for循环读取我们在上面定义的phone和password变量的字符信息,并且每个字符输入间隔了400毫秒,这样做百度指数就认为你是人为的在输入了。
time.sleep(1)action=ActionChains(driver)loginDom = driver.find_element_by_id('TANGRAM__PSP_4__submit')action.move_to_element(loginDom).click().perform()复制代码
当我们输入完成用户名和密码以后我们只需要找到登录按钮的DOM然后进行点击事件就OK了,到这里你就可以成功的绕开百度指数的人机验证了。
四 总结
绕开某一个网站的人机验证,重点在于让机器觉着你是人,而不是它的同类,但是机器觉着你是不是机器的重点在于设计这个机器的人所设置的一些检验手段。
对于百度指数来说它的主要检验手段在于你打开浏览器时的操作,以及输入用户名和密码时的操作,我写这篇文章的时间是2018年11月18日,在这个节点之前呢,我使用上面的方式绕开百度指数的人机验证没有问题,以后有没有问题,或者说有了问题如何解决还是要开发你的大脑了。
本文的最后我附上我全部的代码你可以复制下来,并且安装好对应的python包,以及无头浏览器的环境体验一下。
from selenium import webdriverfrom selenium.webdriver.common.action_chains import ActionChainsimport timeimport sys
word = sys.argv[1] phone = '18846927659' password = 'chitianshi...'
#登录百度指数网站 def login(word, phone, password):
#打开chrome无头浏览器 opt = webdriver.ChromeOptions() opt.set_headless() driver = webdriver.Chrome(options=opt) executor_url = driver.command_executor._url session_id = driver.session_id
#将打开的浏览区url和session_id存储起来,提供给下一次应用 file = open('browserMsg.txt','w') file.writelines([executor_url, 'n',session_id]) file.close()
driver.implicitly_wait(20) driver.set_window_size(1000, 800) driver.get(""+ word +"?words="+ word)
#当你打开无头浏览器时,你需要操作一下浏览器,可以移动浏览器位置,放大或缩小浏览器,否则网站会判定你是爬虫 #在此,我先等待了1秒,然后放大浏览器,然后缩小浏览器,然后等待2秒 time.sleep(1) driver.set_window_size(1200, 800) time.sleep(1) driver.set_window_size(1000, 800) time.sleep(2)
#等待2秒以后输入用户名和密码 #先获取用户名和密码的输入框 getUserPhoneDom = driver.find_element_by_id('TANGRAM__PSP_4__userName') getUserPassDom = driver.find_element_by_id('TANGRAM__PSP_4__password')
#输入用户名和密码的时候不能够一下将用户名全部输入,否则网站会判定你是爬虫,就会让你输入短信验证码 #此处我按照字符输入,并且每个字符输入时,间隔400毫秒 for i in phone: getUserPhoneDom.send_keys(i) time.sleep(.4) #密码的输入同用户名的输入是一个道理 for j in password: getUserPassDom.send_keys(j) time.sleep(.4)
#输入完用户名和密码以后间隔1秒再点击登录按钮 time.sleep(1) #点击登录按钮 action=ActionChains(driver) loginDom = driver.find_element_by_id('TANGRAM__PSP_4__submit') action.move_to_element(loginDom).click().perform()
#网站在登录的时候会偶尔出现验证码,此处是为了判断是否出现验证码,如果出现就重新执行函数 time.sleep(2) try: errorData = driver.find_element_by_id('TANGRAM__PSP_4__error').text if errorData == "请您输入验证码": login(word, phone, password) except: pass
复制代码
login(word, phone, password) #此处是为了让打开的浏览器进行一直运行不关闭,以便于后面使用 root = Tk() root.withdraw() root.mainloop() 复制代码