《Python 3反爬虫原理与绕过实战》初步学习
开发环境配置 安装steamboat Steamboat 由以下3个 Docker 镜像组成
1 2 3 docker pullregistry.cn-hangzhou.aliyuncs.com/steamboat/steamboat:1 docker pullregistry.cn-hangzhou.aliyuncs.com/steamboat/steamboat:2 docker pullregistry.cn-hangzhou.aliyuncs.com/steamboat/steamboat:3
启动多个镜像写shell文件
1 2 3 4 5 6 7 8 9 创建runsp.sh 写入 docker run -d -p 80:80 -p8090:8090 -p 8205:8205 -p 8207:8207 9b5cc6bd42d0 docker run -d -p 8202:8202 0487eb7998d9 docker run -d -p 8206:8206 5c75ec9ef2b6 启动 sh runsp.sh
Splash Splash 是一个异步的 JavaScript 渲染服务。它是带有 HTTP API 的轻量级 Web 浏览器,能够并行处理多个页面请求,可以在页面上下文中执行自定义的 JavaScript 以及模拟浏览器中的点击、下滑等操作。 Splash的安装方式有两种,一种是下载已经封装好的 Docker 镜像,另一种是从 GitHub 下载源码后安装,这里我推荐第一种安装方式。在安装好 Docker 后,只需要从 DockerHub 中拉取 Splash 镜像并运行即可,相关命令如下:
1 docker run -it -p 8050:8050 scrapinghub/splash
Puppeteer Puppeteer 是谷歌官方出品的一个 Node.js库,提供了一个高级 API来控制DevTools协议上的Chrome 或 Chromium。Puppeteer默认无界面运行,但可以配置为运行有界面的 Chrome 或 Chromium。
在用户浏览器中,使用Puppeteer可以完成大多数手动执行的操作。有开发者开源了支持 Python 的 Puppeteer 库,叫作 Pyppeteer,其文档网址为https://miyakogi.github.io/pyppeteer/ 。要注意的是,它仅支持在 Python 3.6 + 的环境下运行。同样,我们可以使用Python 包管理工具 pip来安装 Pyppeteer,命令如下
验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import asynciofrom pyppeteer import launchasync def main (): browser = await launch() page = await browser.newPage() await page.goto('http://example.com' ) await page.screenshot({'path' : 'example.png' }) await browser.close() asyncio.get_event_loop().run_until_complete(main())
第一次运行 Pyppeteer 时,它会下载最新版本的Chromium (大小约 100 MB),所以第一次运行的等待时间较长。命令运行完毕后,在 pyteer.py 的同级目录下就会多出名为 example.png的图片,说明 Pyppeteer 安装成功,且可以正常运行。
PyTesseract 安装: https://blog.csdn.net/spatial_coder/article/details/123938274
pytesseract.py的cmd路径 将cmd路径改为本机Tesseract-OCR.exe所在的路径
1 2 3 4 5 6 7 try : from PIL import Image except ImportError: import Image import pytesseractprint (pytesseract.image_to_string(Image.open ('example.png' )))
首先导入 Image 库和 PyTesseract 库,接着使用 PyTesseract 库中的image_to_string() 方法识别 example.png 图片中的文字,并打印识别结果。
Parsel Parsel 库是 Scrapy 开发团队开源的一个支持 XPath和 CSS 选择器语法的网页解析 库
反爬虫的概念与定义
User-Agent反爬虫 User-Agent 反爬虫指的是服务器端通过校验请求头中的User-Agent值来区分正常用户和爬虫程序的手段,这是一种较为初级的反爬虫手段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import requestsfrom lxml import etreeurl = "http://www.porters.vip/verify/uas/index.html" headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36" } resp = requests.get(url, headers=headers) print (resp.status_code)html = etree.HTML(resp.text) if resp.status_code == 200 : divs = html.xpath('/html/body/div[2]/div[2]/div' ) for a in divs: biaoti = a.xpath('./div/h4[1]/a[1]/text()' ) print (biaoti) else : print ('This request is fial.' )
User-Agent校验流程 利用 nginx 的条件判断语句实现反爬虫。比如将 Python、Java和 PHP 等关键词加入黑名单,那么只要服务器检测到User-Agent头域值中包含黑名单中的关键词时,就会将此次请求的发起者视为爬虫,可以不予处理或者返回相应的错误提示。
示例
在nginx 的辅助配置文件目录下新建一个名为 porters.conf 的辅助配置,将以下配置写入文件:
1 2 3 4 5 6 7 8 9 10 11 12 server { listen 80; server_name www.porters.vip; # 请填写真实域名 charset utf-8; location /verify/uas/ { if ($http_user_agent ~* (python)){ return 403; } root /root/www/html; index index.html; } }
这段配置的作用是判断请求头信息中User-Agent头域值里是否包含关键字python ,如果包含,则直接返回 403 错误。注意,配置中的server_name 必须是域名或 IP 地址,否则无法访问。然后,在 root 指令设定的目录下建立层级目录 /verify/uas。
Cookie反爬虫 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import requestsfrom lxml import etreeurl = 'http://www.porters.vip/verify/cookie/content.html' header = {"Cookie" : "isfirst=789kq7uc1pp4c" } resp = requests.get(url, headers=header) print (resp.status_code)if resp.status_code == 200 : html = etree.HTML(resp.text) res = html.cssselect('.page-header h1' )[0 ].text print (res) else : print ('This request is fial.' )
签名验证反爬虫 http://www.porters.vip/verify/sign/
页面加载了两个js文件一个md5加密的js文件,一个sign.js文件,sign.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 function fetch ( ){ text=$.ajax ({ type :"GET" , async : false , url :"http://www.porters.vip/verify/sign/fet" + uri () }); $("#content" ).html (text.responseText ); } function randints (r, n, tof ){var result = [];if (tof){return Math .floor (Math .random ()*r);} for (var i=0 ;i<n;i++){s = Math .floor (Math .random ()*r); result.push (s); } return result.join ('' );} function randstrs (n ){var result = [];for (var i=0 ; i<n; i++){s = String .fromCharCode (65 +randints (25 , 1 , 1 )); result.push (s); } return result.join ('' );} function uri ( ){var action = randints (9 , 5 , 0 );var tim = Math .round (new Date ().getTime ()/1000 ).toString ();var randstr = randstrs (5 );var hexs = hex_md5 (action+tim+randstr);args = '?actions=' + action + '&tim=' + tim + '&randstr=' + randstr + '&sign=' + hexs; return args;}
直接看最后可以得知,action,tim,randstr,hexs这几个值
action是生成1-9的几个随机数
tim时间戳
randstr是生成5个随机字母代码得知是大写字母
hexs将前面所有的值加起来md5加密
python实现相同代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from time import timefrom random import randint, sampleimport hashlibdef hex5 (value ): manipulator = hashlib.md5() manipulator.update(value.encode('utf-8' )) return manipulator.hexdigest() action = "" .join([str (randint(1 , 9 )) for _ in range (5 )]) print (action)tim = round (time()) randstr = "" .join(sample([chr (_) for _ in range (65 , 91 )], 5 )) value = action + str (tim) + randstr hexs = hex5(value) print (action, tim, randstr, hexs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from time import timefrom random import randint, sampleimport hashlibimport requestsdef hex5 (value ): manipulator = hashlib.md5() manipulator.update(value.encode('utf-8' )) return manipulator.hexdigest() action = "" .join([str (randint(1 , 9 )) for _ in range (5 )]) print (action)tim = round (time()) randstr = "" .join(sample([chr (_) for _ in range (65 , 91 )], 5 )) value = action + str (tim) + randstr hexs = hex5(value) print (action, tim, randstr, hexs)def uri (): args = '?actions={}&tim={}&randstr={}&sign={}' .format (action, tim, randstr, hexs) return args url = 'http://www.porters.vip/verify/sign/fet' + uri() print (url)resp = requests.get(url) print (resp.status_code, resp.text)
本次的反爬虫利用 JavaScript 生成随机值,与之前的随机值不同,这次的随机值中包含时间戳和 MD5 加密值。签名验证有很多种实现方式,但原理都是相同的:由客户端生成一些随机值和不可逆的 MD5 加密字符串,并在发起请求时将这些值发送给服务器端。服务器端使用相同的方式对随机值进行计算以及 MD5 加密,如果服务器端得到的MD5 值与前端提交的 MD5 值相等,就代表是正常请求,否则返回403。
动态渲染反爬虫 动态网页比静态网页更具交互性,能给用户提供更好的体验。动态网页中常见的表现形式有下拉刷新、点击切换和悬停显示等。由JavaScript 改变 HTML DOM 导致页面内容发生变化的现象称为动态渲染。很多时候开发者只是想完成某个交互功能,而不是特意区分正常用户和爬虫程序,但这在不经意间限制了爬虫对数据的获取。由于编程语言没有像浏览器一样内置 JavaScript 解释器和渲染引擎,所以动态渲染是天然的反爬虫手段。
Selenium套件 Selenium 是一个用于测试Web应用程序的工具。我们可以通过Selenium 和浏览器驱动调用浏览器执行特定的操作,如发起网络请求、点击操作、鼠标下滑等。由于调用的是浏览器,所以这种组合还具备了资源自动加载和渲染的能力。
1 2 3 4 5 6 7 8 9 10 11 from selenium.webdriver import Chromefrom selenium.webdriver.common.by import Byimport timeurl = 'http://www.porters.vip/verify/sign/' web = Chrome() web.get(url) web.find_element(By.XPATH, '//*[@id="fetch_button"]' ).click() time.sleep(1 ) resp = web.page_source print (resp)
异步渲染库Puppeteer 在 Selenium 套件的支持下,我们很轻松地完成了爬取任务。但Selenium 套件也有一定的缺陷,当我们使用 Python 中的异步库编写爬虫时,Selenium 就不是那么适合了。异步是目前提升爬虫效率的常用手段之一,越来越多的人将同步的爬虫代码改为异步。由于浏览器是以进程的方式启动,所以它无法满足异步爬虫的渲染需求,为什么这么说呢?异步爬虫可以做到每秒向 300 个页面发起请求,但是要在计算机中开启 300 个浏览器进程或者 300 个标签页是很困难的,这会导致阻塞,影响异步爬虫程序的整体效率。我们可以用 Python 代 码验证一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from selenium import webdriverfrom datetime import datetimestarts = datetime.now() url = 'http://www.porters.vip/verify/sign/' browser = webdriver.Chrome() for i in range (30 ): browser.get(url) resp = browser.page_source browser.quit() runtime = datetime.now() - starts print (runtime.total_seconds())
selenium循环访问示例页面总共耗时7秒左右
Puppeteer是 Google 开源的 Node 库,它提供了一个高级 API来控制 Chrome 浏览器,浏览器中大多数手动执行的操作都可以使用Puppeteer 完成,更重要的是 Puppeteer 支持异步。Puppeteer 是一个 Node 库,如果你的爬虫程序是用 Node.js编写的,那么可以直接使用这个库,如果爬虫程序是用 Python 编写的,那么就需要用支持Python 的库 Pyppeteer。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import asynciofrom pyppeteer import launchasync def main (): browser = await launch() page = await browser.newPage() await page.goto('http://www.porters.vip/verify/sign' ) await page.click('#fetch_button' ) resp = await page.xpath('//*[@id="content"]' ) text = await (await resp[0 ].getProperty('textContent' )).jsonValue() print (text) await browser.close() asyncio.get_event_loop().run_until_complete(main())
说明 Puppeteer 也可以完成点击操作和页面渲染任务。
异步渲染服务 Splash Splash 是一个异步的 JavaScript 渲染服务,它是带有 HTTP API 的轻量级 Web 浏览器。 Splash能够并行地处理多个页面请求,在页面上下文中执行自定义的 JavaScript 以及模浏览器中的点击、下滑等操作。有了 Splash 之后情况就变得不一样了,我们可以将Splash 服务部署到云服务器上并配置负载均衡。
Splash 服务提供了一个可视化的操作界面
界面左侧是一些介绍文字,右侧是命令框。我们可以在右侧地址栏输入网址,点击Render me按钮后 Splash 就会向该网址发出请求。在右侧命令框中是 Splash 预设的示例代码,这段代码的作用是向指定网址发出请求,并在等待 0.5 秒后将页面文本、页面截图和资源加载相关信息返回。我们可以在可视化界面中尝试访问http://www.porters.vip/verify/sign,然后点击对应的按钮并打印渲染后的文本内容。
更改命令行代码,点击按钮,提取网页文本
1 2 3 4 5 6 7 8 9 10 11 12 function main (splash, args) assert (splash:go(args.url)) local butt = splash:select ('#fetch_button' ) butt:mouse_click() content = splash:select ('#content' ):text() return { results = content } end
Splash 允许我们编写自定义的 Lua 脚本,如果要获取脚本运行结果,那么我们可以使用execute 接口,execute 的详细介绍可参考Splash 文档中的 Splash Script 教程
详见:https://splash.readthedocs.io/en/stable/scriptingtutorial.html#scripting-tutorial
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import requestsimport jsonrender = 'http://192.168.136.133:8050/execute' script = """ function main(splash) splash:go('http://www.porters.vip/verify/sign/') local butt = splash:select('#fetch_button') butt:mouse_click() content = splash:select('#content'):text() return { result = content } end """ header = {'content-type' : 'application/json' } data = json.dumps({"lua_source" : script}) resp = requests.post(render, data=data, headers=header) print (resp.json())
Splash 渲染服务同样可以完成点击事件和目标内容的提取。
图灵社区 1 <input type ="search" name ="q" placeholder ="技术改变世界 阅读塑造人生" class ="key" >
Selenium 1 2 3 4 5 6 7 8 from selenium import webdriverurl = 'http://www.ituring.com.cn/' browser = webdriver.Chrome() browser.get(url) browser.find_element_by_css_selector('.key' ).send_keys('Python' )
Puppeteer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import asynciofrom pyppeteer import launchasync def main (): browser = await launch() page = await browser.newPage() await page.goto('http://www.ituring.com.cn' ) await page.type ('.key' , 'python' ) await page.screenshot({'path' : 'ituring.png' }) await browser.close() asyncio.get_event_loop().run_until_complete(main())
Splash 1 2 3 4 5 6 7 8 9 10 11 12 13 function main (splash, args) assert (splash:go(args.url)) assert (splash:wait(0.2 )) splash:select ('input[name=q]' ):focus() splash:send_text('Python' ) assert (splash:wait(0.2 )) return { png = splash:png() } end
Splash 页面左侧输出了图灵社区页面截图,并且截图中的搜索框文本内容也变成了Python。运行结果说明这3种工具都能够模拟人类对浏览器的操作。
设置禁止渲染工具加载图片或其他类型文件
书228页
图片伪装反爬虫 http://www.porters.vip/confusion/recruit.html
电话这里是一张图片
任务:爬取企业名称及联系电话
企业名称
1 2 3 4 5 6 7 8 9 import requestsfrom parsel import Selectorurl = 'http://www.porters.vip/confusion/recruit.html' resp = requests.get(url) sel = Selector(resp.text) company = sel.css('h1.interval::text' ).get() print (company)
电话号码用ocr识别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import ioimport requestsfrom urllib.parse import urljoinfrom parsel import Selectorfrom PIL import Imageimport pytesseracturl = 'http://www.porters.vip/confusion/recruit.html' resp = requests.get(url) sel = Selector(resp.text) image_name = sel.css('.pn::attr("src")' ).extract_first() image_url = urljoin(url, image_name) image_body = requests.get(image_url).content image_stream = Image.open (io.BytesIO(image_body)) print (pytesseract.image_to_string(image_stream))
css偏移反爬虫 http://www.porters.vip/confusion/flight.html
大概就是把上面的数排列好,然后用上面的多少px去对应他,第几位就是几,然后把所有数写出来,为764,倒序一下就位467
大概是这样,
WebDriver 识别 http://www.porters.vip/features/webdriver.html
借助”其实是通过对应的浏览器驱动(即WebDriver)向浏览器发出指令的行为。也就是说,开发者可以根据客户端是否包含浏览器驱动这一特征来区分正常用户和爬虫程序。
任务:爬取新闻专题页中的文章内容
selenium和pyppeteer无法获取目标数据
navigator.webdriver判断了是否使用webdriver驱动
绕过方法
Splash
对于 Splash 这种使用 WebKit 内核开发的渲染工具来说是无效的。我们可以用 Splash 获取示例 8 中的目标数据,Splash 脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function main (splash, args) assert (splash:go(args.url)) assert (splash:wait(0.5 )) local bton = splash:select ('.btn.btn-primary.btn-lg' ) assert (splash:wait(1 )) bton:mouse_hover() bton:mouse_click() assert (splash:wait(1 )) return { png = splash:png(), } end
识别navigator.webdriver值,可以在触发之前将值改为false 或者undefined 即可。
Selenium 套件和 Puppeteer 都提供了运行 JavaScript 代码的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from selenium.webdriver import Chromefrom selenium.webdriver.common.by import Byimport timebrowser = Chrome() browser.get('http://www.porters.vip/features/webdriver.html' ) script = 'Object.defineProperty(navigator, "webdriver", {get: () => false,});' browser.execute_script(script) time.sleep(1 ) browser.find_element(By.CSS_SELECTOR, '.btn.btn-primary.btn-lg' ).click() element = browser.find_element(By.CSS_SELECTOR, '#content' ) time.sleep(1 ) print (element.text)browser.close()
修改之后的javascript只对当前的页面有效
浏览器特征 比如将浏览器请求头中的User-Agent 值与navigator.userAgent 属性值进行对比,结合navigator.platform 就可以判断客户端是否使用随机切换的UserAgent。
爬虫特征 访问频率限制
http://www.porters.vip/features/rate.html
1 2 3 4 import requestsfor i in range (10 ): resp = requests.get('http://www.porters.vip/features/rate.html' ) print (resp.status_code)
直接访问4个503
方法1:加time.sleep(1)
方法2:分布式爬虫
方法3:代理池
浏览器指纹 1 2 3 4 <script > console .log ("userAgent:" + navigator.userAgent ); console .log ("platform:" + navigator.platform ); </script >
获取ua和设备信息,判断客户端是否使用随机切换的User-Agent
Splash 1 2 3 4 5 6 7 8 9 10 11 import asynciofrom pyppeteer import launchasync def main (): browser = await launch() page = await browser.newPage() await page.goto('http://www.porters.vip/features/browser.html' ) await page.setViewport({'width' : 1000 , 'height' : 1000 }) await page.screenshot({'path' : 'browser.png' }) await browser.close() asyncio.get_event_loop().run_until_complete(main())
Splash用linux搭建的,就会显示为linux
Puppeteer截图
如果判断比较明显的客户端特征,比较离谱的就是爬虫的客户端,可以做为特征。
字符验证码 网址 :http://www.porters.vip/captcha/words.html 。 任务 :使用程序通过登录界面中的字符验证码校验。
保存验证码图片,尝试识别
1 2 3 4 5 6 7 import pytesseractfrom os import pathimages = path.join(path.dirname(path.abspath(__file__)), 'images/words.png' ) print (pytesseract.image_to_string(images))
返回为空,说明并没有被识别
本节所面对的是带有彩色背景斜线和噪点图片,而且图片中的字符颜色与背景色并没有强烈的反差,这些因素都会影响识别效果。要想提高识别的成功率,我们必须对图片进行处理,例如降低斜线和噪点对文字的干扰,增强背景色与字符颜色的反差。也就是说,我们需要对图片进行灰度处理(去掉彩色)和二值化处理(降低干扰、增强颜色反差)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import pytesseractfrom os import pathfrom PIL import Imagedef handler (grays, threshold=190 ): """ 对灰度图片进行二值化处理 默认阈值为160,可根据实际情况调整 """ table = [] for i in range (256 ): if i < threshold: table.append(0 ) else : table.append(1 ) anti = grays.point(table, '1' ) return anti images = path.join(path.dirname(path.abspath(__file__)), 'images/words.png' ) gray = Image.open (images).convert('L' ) images = handler(gray) images.show() print (pytesseract.image_to_string(images))
测试 190的二值化处理最合适,但是googleocr依旧没办法识别
卷积网络 跳过
计算型验证码 网址 :http://www.porters.vip/captcha/mathes.html 。 任务 :使用程序通过登录页面中的计算型验证码校验。
1 2 3 4 5 6 7 8 from PIL import Imageimport pytesseractfrom os import pathimages = path.join(path.dirname(path.abspath(__file__)), 'images/mathes.png' ) print (pytesseract.image_to_string(images))
能正常识别
提权其中的数字和运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from PIL import Imageimport pytesseractfrom os import pathimport reimages = path.join(path.dirname(path.abspath(__file__)), 'images/mathes.png' ) strings = pytesseract.image_to_string(images) string = re.findall('\d+' , strings) operator = re.findall('[+|\-|\*]' , strings) def operator_func (a: int , b: int , oper: str ) -> int : if oper == '+' : return a + b if oper == '-' : return a - b if oper == '*' : return a * b res = operator_func(int (string[0 ]), int (string[1 ]), operator[0 ]) print (res)
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 from PIL import Imageimport pytesseractfrom os import pathimport reimages = path.join(path.dirname(path.abspath(__file__)), 'images/mathes2.png' ) def handler (grays, threshold=30 ): """ 对灰度图片进行二值化处理 默认阈值为160,可根据实际情况调整 """ table = [] for i in range (256 ): if i < threshold: table.append(0 ) else : table.append(1 ) anti = grays.point(table, '1' ) return anti gray = Image.open (images).convert('L' ) images = handler(gray) images.show() def operator_func (a: int , b: int , oper: str ) -> int : if oper == '+' : return a + b if oper == '-' : return a - b if oper == '*' : return a * b strings = pytesseract.image_to_string(images) string = re.findall('\d+' , strings) operator = re.findall('[+|\-|\*]' , strings) res = operator_func(int (string[0 ]), int (string[1 ]), operator[0 ]) print (res)
能识别
滑动验证码 网址 :http://www.porters.vip/captcha/sliders.html 任务 :使用程序通过登录界面中滑动验证码的校验
流程:
打开页面鼠标移动到滑块位置
按下鼠标将滑块拖拽到滑轨终点位置
放开鼠标,等待验证结果
Selenium 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import timefrom selenium.webdriver import Chromefrom selenium import webdriverfrom selenium.webdriver.common.by import Bybrowser = Chrome() browser.get('http://www.porters.vip/captcha/sliders.html?' ) browser.find_element(By.XPATH, '//*[@id="inputEmail3"]' ).send_keys('123123@qq.com' ) browser.find_element(By.XPATH, '//*[@id="inputPassword3"]' ).send_keys('123123123' ) hover = browser.find_element(By.CSS_SELECTOR, '.hover' ) action = webdriver.ActionChains(browser) action.click_and_hold(hover).perform() action.move_by_offset(340 , 0 ) action.release().perform() time.sleep(1 ) browser.find_element(By.XPATH, '/html/body/div[2]/div[2]/form/div[4]/div/button' ).click() time.sleep(1 )
滑动拼图验证码 网址 :http://www.porters.vip/captcha/jigsaw.html 。 爬虫任务 :使用程序通过滑动拼图验证码的校验。
滑块和滑块的区域是可以获取到的,提取里面的值,后者减去前者,移动距离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from selenium import webdriverfrom selenium.webdriver.common.by import Byimport refrom parsel import Selectorweb = webdriver.Chrome() web.get('http://www.porters.vip/captcha/jigsaw.html' ) jigsawCircle = web.find_element(By.CSS_SELECTOR, '#jigsawCircle' ) action = webdriver.ActionChains(web) action.click_and_hold(jigsawCircle).perform() html = web.page_source sel = Selector(html) mbk_style = sel.css('#missblock::attr("style")' ).get() tbk_style = sel.css('#targetblock::attr("style")' ).get() extract = lambda x: '' .join(re.findall('left: (\d+|\d+.\d+)px' , x)) mbk_style = extract(mbk_style) tbk_style = extract(tbk_style) distance = float (tbk_style) - float (mbk_style) action.move_by_offset(distance, 0 ) action.release().perform()
文字点选验证码 网址 :http://www.porters.vip/captcha/clicks.html 任务 :编写程序通过登录页面的文字点选验证码校验。
涉及深度学习,暂时跳过
获取需要识别的文字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import reimport timefrom selenium import webdriverfrom parsel import Selectorurl = 'http://www.porters.vip/captcha/clicks.html' web = webdriver.Chrome() web.get(url) time.sleep(1 ) html = Selector(web.page_source) print (html)require = html.css('#divTips::text' ).get() target = re.findall('"(.)"' , require) print (target)
v1.5.2