├── 10 ├── 10-1 │ ├── __init__.py │ ├── 10-1-3-one.py │ ├── public.pem │ ├── 10-1-5-one.py │ ├── private.pem │ ├── 10-1-6-one.py │ └── custom64.py ├── 10-2 │ ├── __init__.py │ ├── parse.js │ └── 10-2-4-two.js └── 10-3 │ ├── 10-3-1-two.html │ ├── 10-3-1-one.html │ └── 10-3-2-one.html ├── 02 └── 2-3 │ ├── __init__.py │ └── websocket.py ├── 04 ├── 4-1 │ ├── __init__.py │ ├── 4-1-1-one.py │ └── 4-1-1-two.py ├── 4-2 │ ├── __init__.py │ ├── 4-2-1-one.py │ ├── 4-2-1-two.py │ └── fet.js ├── 4-3 │ ├── __init__.py │ ├── 4-3-2 │ │ ├── __init__.py │ │ ├── static │ │ │ ├── sign.js │ │ │ └── md5.js │ │ ├── 4-3-2-one.py │ │ └── template │ │ │ └── index.html │ ├── 4-3-1-one.py │ └── sign.js ├── 4-4 │ ├── __init__.py │ ├── client.py │ └── server.py ├── 4-5 │ ├── __init__.py │ ├── client.py │ └── server.py └── __init__.py ├── 05 └── 5-2 │ ├── __init__.py │ ├── ituring.png │ ├── 5-2-1-one.py │ ├── 5-2-5-one.py │ ├── 5-2-1-two.py │ ├── 5-2-1-three.py │ ├── 5-2-2-one.py │ ├── 5-2-5-two.py │ ├── 5-2-2-two.py │ └── 5-2-3-one.py ├── 06 ├── 6-1 │ ├── __init__.py │ ├── 6-1-1-one.py │ └── 6-1-1-two.py ├── 6-2 │ ├── __init__.py │ └── 6-2-1-one.py ├── 6-3 │ ├── __init__.py │ ├── 6-3-1-one.py │ ├── 6-3-1-two.py │ └── 6-3-3-one.py ├── 6-4 │ ├── __init__.py │ ├── movie.woff │ ├── target.woff │ ├── 6-4-2-one.py │ └── 6-4-2-two.py └── 6-5 │ ├── __init__.py │ ├── ganrao.png │ ├── total.png │ ├── 6-5-2-one.py │ └── 6-5-1-one.py ├── 07 ├── 7-1 │ ├── __init__.py │ ├── webdriver.png │ ├── 7-1-1-one.py │ ├── 7-1-1-two.py │ └── 7-1-3-one.py ├── 7-2 │ ├── __init__.py │ ├── browser.png │ └── 7-2-1-one.py ├── 7-3 │ ├── __init__.py │ ├── 7-3-2-one.py │ ├── 7-3-1-one.py │ └── 7-3-1-two.py └── 7-4 │ ├── __init__.py │ ├── static │ ├── magic_2.png │ ├── mate_20.png │ ├── huawei_p30.png │ ├── mate_20_x.png │ ├── mate_20_pro.png │ └── huawei_p30_pro.png │ ├── 7-4-1-one.py │ ├── hidden.py │ └── template │ └── details.html ├── 08 ├── 8-1 │ ├── __init__.py │ └── 8-1-1-one.py └── 8-2 │ ├── __init__.py │ └── 8-2-2-one.py ├── 09 ├── 9-1 │ ├── __init__.py │ ├── images │ │ └── words.png │ ├── 9-1-1-one.py │ ├── 9-1-1-two.py │ └── 9-1-1-three.py ├── 9-2 │ ├── __init__.py │ ├── images │ │ └── mathes.png │ ├── 9-2-1-one.py │ └── 9-2-1-two.py ├── 9-3 │ ├── __init__.py │ └── 9-3-1-one.py ├── 9-4 │ ├── __init__.py │ ├── after.png │ ├── before.png │ ├── 9-4-5-one.py │ ├── 9-4-1-one.py │ └── 9-4-5-two.py ├── 9-5 │ ├── __init__.py │ └── 9-5-1-one.py ├── 9-6 │ ├── __init__.py │ ├── 9-6-one.py │ ├── 9-6-two.py │ └── 9-6-three.py ├── .DS_Store └── captcha │ ├── .DS_Store │ ├── images │ ├── 0.jpg │ ├── 1.jpg │ ├── 2.jpg │ └── 3.jpg │ ├── css │ ├── clicks.css │ ├── sliders.css │ ├── jigsaw.css │ └── jigsawCanvas.css │ ├── js │ ├── common.js │ ├── words.js │ ├── mathes.js │ ├── sliders.js │ ├── jigsaw.js │ ├── jigsawCanvas.js │ ├── jigsawCanvas.html │ └── clicks.js │ ├── jigsawCanvas.js │ ├── mousemove.html │ ├── clicks.html │ ├── nomal.html │ ├── words.html │ ├── mathes.html │ ├── sliders.html │ ├── jigsawCanvas.html │ └── jigsaw.html ├── .DS_Store ├── .idea ├── vcs.xml ├── misc.xml ├── modules.xml ├── antispider.iml └── workspace.xml └── README.md /02/2-3/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/4-1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/4-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/4-3/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/4-4/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/4-5/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /05/5-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06/6-1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06/6-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06/6-3/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06/6-4/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06/6-5/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /07/7-1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /07/7-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /07/7-3/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /07/7-4/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /08/8-1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /08/8-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09/9-1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09/9-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09/9-3/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09/9-4/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09/9-5/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09/9-6/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10/10-1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10/10-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04/4-3/4-3-2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/.DS_Store -------------------------------------------------------------------------------- /09/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/.DS_Store -------------------------------------------------------------------------------- /05/5-2/ituring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/05/5-2/ituring.png -------------------------------------------------------------------------------- /06/6-4/movie.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/06/6-4/movie.woff -------------------------------------------------------------------------------- /06/6-4/target.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/06/6-4/target.woff -------------------------------------------------------------------------------- /06/6-5/ganrao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/06/6-5/ganrao.png -------------------------------------------------------------------------------- /06/6-5/total.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/06/6-5/total.png -------------------------------------------------------------------------------- /07/7-2/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-2/browser.png -------------------------------------------------------------------------------- /09/9-4/after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/9-4/after.png -------------------------------------------------------------------------------- /09/9-4/before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/9-4/before.png -------------------------------------------------------------------------------- /07/7-1/webdriver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-1/webdriver.png -------------------------------------------------------------------------------- /09/captcha/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/captcha/.DS_Store -------------------------------------------------------------------------------- /09/9-1/images/words.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/9-1/images/words.png -------------------------------------------------------------------------------- /09/captcha/images/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/captcha/images/0.jpg -------------------------------------------------------------------------------- /09/captcha/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/captcha/images/1.jpg -------------------------------------------------------------------------------- /09/captcha/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/captcha/images/2.jpg -------------------------------------------------------------------------------- /09/captcha/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/captcha/images/3.jpg -------------------------------------------------------------------------------- /06/6-5/6-5-2-one.py: -------------------------------------------------------------------------------- 1 | import pytesseract 2 | #识别结果 3 | print(pytesseract.image_to_string('ganrao.png')) 4 | -------------------------------------------------------------------------------- /07/7-4/static/magic_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-4/static/magic_2.png -------------------------------------------------------------------------------- /07/7-4/static/mate_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-4/static/mate_20.png -------------------------------------------------------------------------------- /09/9-2/images/mathes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/09/9-2/images/mathes.png -------------------------------------------------------------------------------- /07/7-4/static/huawei_p30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-4/static/huawei_p30.png -------------------------------------------------------------------------------- /07/7-4/static/mate_20_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-4/static/mate_20_x.png -------------------------------------------------------------------------------- /07/7-4/static/mate_20_pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-4/static/mate_20_pro.png -------------------------------------------------------------------------------- /07/7-4/static/huawei_p30_pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rockyzsu/antispider/master/07/7-4/static/huawei_p30_pro.png -------------------------------------------------------------------------------- /06/6-4/6-4-2-one.py: -------------------------------------------------------------------------------- 1 | from fontTools.ttLib import TTFont 2 | font = TTFont('movie.woff') # 打开当前目录的movie.woff文件 3 | font.saveXML('movie.xml') # 另存为movie.xml -------------------------------------------------------------------------------- /07/7-3/7-3-2-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | for i in range(10): 3 | resp = requests.get('http://www.porters.vip:8090/rate.html') 4 | print(resp.status_code) -------------------------------------------------------------------------------- /07/7-3/7-3-1-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | for i in range(10): 4 | resp = requests.get('http://www.porters.vip/features/rate.html') 5 | print(resp.status_code) -------------------------------------------------------------------------------- /09/captcha/css/clicks.css: -------------------------------------------------------------------------------- 1 | .divTips { 2 | border: 1px solid #e0e0e0; 3 | font-size: 16px; 4 | height: 30px; 5 | line-height: 30px; 6 | text-align: center; 7 | } -------------------------------------------------------------------------------- /10/10-2/parse.js: -------------------------------------------------------------------------------- 1 | var UglifyJS = require("uglify-js"); 2 | var ast = UglifyJS.parse("function sum(x, y){ return x + y }"); 3 | console.log(ast) 4 | console.log(ast.body[0].name.name) -------------------------------------------------------------------------------- /05/5-2/5-2-1-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | url = 'http://www.porters.vip/verify/sign' 4 | # 初始化浏览器对象 5 | browser = webdriver.Chrome() 6 | # 向指定网址发起GET请求 7 | browser.get(url) -------------------------------------------------------------------------------- /10/10-1/10-1-3-one.py: -------------------------------------------------------------------------------- 1 | from base64 import b64decode 2 | 3 | code = ['d3d3Lmh1YXdlaS5jb20=', 'd3d3Lmp1ZWppbi5pbQ=='] 4 | for c in code: 5 | string = b64decode(c).decode('utf8') 6 | print(string) -------------------------------------------------------------------------------- /07/7-3/7-3-1-two.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | 4 | for i in range(10): 5 | resp = requests.get('http://www.porters.vip/features/rate.html') 6 | print(resp.status_code) 7 | time.sleep(1) -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /08/8-1/8-1-1-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | resp = requests.get('http://www.porters.vip:8207/api/v1/') 5 | # 将响应正文转换成python容器对象 6 | data = json.loads(resp.text) 7 | print(type(data)) 8 | for i in data: 9 | print(i) -------------------------------------------------------------------------------- /09/9-1/9-1-1-one.py: -------------------------------------------------------------------------------- 1 | import pytesseract 2 | from os import path 3 | 4 | # 保存在本地的验证码图片 5 | images = path.join(path.dirname(path.abspath(__file__)), 'images/words.png') 6 | # 使用pytesseract库识别验证码中的字符并打印 7 | print(pytesseract.image_to_string(images)) -------------------------------------------------------------------------------- /09/9-6/9-6-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | browser = webdriver.Chrome() 3 | # 访问指定URL 4 | browser.get('http://www.porters.vip/captcha/mousemove.html') 5 | # 定位页面中的first按钮 6 | button = browser.find_element_by_class_name('button1') 7 | # 点击first按钮 8 | button.click() -------------------------------------------------------------------------------- /05/5-2/5-2-5-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | url = 'http://www.ituring.com.cn/' 4 | # 初始化浏览器对象 5 | browser = webdriver.Chrome() 6 | # 向指定网址发起GET请求 7 | browser.get(url) 8 | # 使用CSS选择器定位搜索框,并输入文字 9 | browser.find_element_by_css_selector('.key').send_keys('Python') -------------------------------------------------------------------------------- /10/10-3/10-3-1-two.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

今天天气真好,下午去海滩游玩。

4 | 10 | 11 | -------------------------------------------------------------------------------- /10/10-3/10-3-1-one.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

今天天气真好,下午去海滩游玩。

4 | 10 | 11 | -------------------------------------------------------------------------------- /10/10-1/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcL0c4oVjmgp0QxA5PMDo2XwIW 3 | DFXAPnyuvZ1NFOgCAe3utPOxaAoXxyRFPlQIZXaRSVNCPxzALLBWpXb+j+j9m3yQ 4 | BCY4746BA/dxF8zaKt1bkS9YVWK+zJGTe9rt0LmcSUJLKJqcui+PRbTLD/xi8rPU 5 | 4cqHxfZZMQ2WAnnoLwIDAQAB 6 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /06/6-1/6-1-1-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from parsel import Selector 3 | url = 'http://www.porters.vip/confusion/recruit.html' 4 | # 向目标网址发起请求 5 | resp = requests.get(url) 6 | # 使用响应正文初始化Selector 7 | sel = Selector(resp.text) 8 | # 取出响应正文中的企业名称 9 | company = sel.css('h1.interval::text').get() 10 | print(company) -------------------------------------------------------------------------------- /06/6-3/6-3-1-one.py: -------------------------------------------------------------------------------- 1 | # 定义映射关系 2 | mappings = {'vhk08k': 0, 'vhk6zl': 1, 'vhk9or': 2, 3 | 'vhkfln': 3, 'vhkbvu': 4, 'vhk84t': 5, 4 | 'vhkvxd': 6, 'vhkqsc': 7, 'vhkjj4': 8, 5 | 'vhk0f1': 9} 6 | # HTML中得到的属性值 7 | html_d_class = 'vhkvxd' 8 | # 将映射后的结果打印输出 9 | print(mappings.get(html_d_class)) -------------------------------------------------------------------------------- /09/9-2/9-2-1-one.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PIL import Image 3 | except ImportError: 4 | import Image 5 | import pytesseract 6 | from os import path 7 | 8 | # 保存在本地的验证码图片路径 9 | images = path.join(path.dirname(path.abspath(__file__)), 'images/mathes.png') 10 | # 使用pytesseract库识别图中计算题并打印 11 | print(pytesseract.image_to_string(images)) -------------------------------------------------------------------------------- /10/10-3/10-3-2-one.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

用户无法通过快捷键“F12”唤起开发者工具。

4 | 11 | 12 | -------------------------------------------------------------------------------- /09/9-1/9-1-1-two.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PIL import Image 3 | except ImportError: 4 | import Image 5 | import pytesseract 6 | from os import path 7 | 8 | # 保存在本地的验证码图片路径 9 | images = path.join(path.dirname(path.abspath(__file__)), 'images/words.png') 10 | # 图片灰度处理 11 | gray = Image.open(images).convert('L') 12 | # 显示处理后的图片 13 | gray.show() -------------------------------------------------------------------------------- /05/5-2/5-2-1-two.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | url = 'http://www.porters.vip/verify/sign' 4 | # 初始化浏览器对象 5 | browser = webdriver.Chrome() 6 | # 向指定网址发起GET请求 7 | browser.get(url) 8 | # 使用CSS选择器定位按钮,并点击按钮 9 | browser.find_element_by_css_selector('#fetch_button').click() 10 | # 将按钮点击后的网页文本赋值给变量resp 11 | resp = browser.page_source 12 | print(resp) 13 | # 程序退出,关闭浏览器 14 | browser.quit() -------------------------------------------------------------------------------- /09/9-5/9-5-1-one.py: -------------------------------------------------------------------------------- 1 | import re 2 | from selenium import webdriver 3 | from parsel import Selector 4 | 5 | 6 | url = 'http://www.porters.vip/captcha/clicks.html' 7 | browser = webdriver.Chrome() 8 | browser.get(url) 9 | html = Selector(browser.page_source) 10 | # 获取验证要求 11 | require = html.css('#divTips::text').get() 12 | # 用正则提取验证要求中的文字 13 | target = re.findall('“(.)”', require) 14 | print(target) -------------------------------------------------------------------------------- /07/7-1/7-1-1-one.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver import Chrome 2 | import time 3 | 4 | browser = Chrome() 5 | browser.get('http://www.porters.vip/features/webdriver.html') 6 | # 定位按钮并点击 7 | browser.find_element_by_css_selector('.btn.btn-primary.btn-lg').click() 8 | # 定位到文章内容元素 9 | elements = browser.find_element_by_css_selector('#content') 10 | time.sleep(1) 11 | # 打印文章内容 12 | print(elements.text) 13 | browser.close() -------------------------------------------------------------------------------- /05/5-2/5-2-1-three.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | url = 'http://www.porters.vip/verify/sign' 4 | # 初始化浏览器对象 5 | browser = webdriver.Chrome() 6 | # 向指定网址发起GET请求 7 | browser.get(url) 8 | # 使用CSS选择器定位按钮,并点击按钮 9 | browser.find_element_by_css_selector('#fetch_button').click() 10 | # 使用CSS选择器定位文本,并取出文本内容 11 | resp = browser.find_element_by_css_selector('#content').text 12 | print(resp) 13 | # 程序退出,关闭浏览器 14 | browser.quit() -------------------------------------------------------------------------------- /05/5-2/5-2-2-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from datetime import datetime 3 | # 记录开始时间 4 | starts = datetime.now() 5 | url = 'http://www.porters.vip/verify/sign' 6 | # 初始化浏览器对象 7 | browser = webdriver.Chrome() 8 | for i in range(30): 9 | # 循环30次访问目标url 10 | browser.get(url) 11 | resp = browser.page_source 12 | browser.quit() 13 | # 计算并打印耗时秒数 14 | runtime = datetime.now() - starts 15 | print(runtime.total_seconds()) -------------------------------------------------------------------------------- /07/7-2/7-2-1-one.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyppeteer import launch 3 | 4 | async def main(): 5 | browser = await launch() 6 | page = await browser.newPage() 7 | await page.goto('http://www.porters.vip/features/browser.html') 8 | await page.setViewport({'width': 1000, 'height': 1000}) 9 | await page.screenshot({'path': 'browser.png'}) 10 | await browser.close() 11 | 12 | asyncio.get_event_loop().run_until_complete(main()) -------------------------------------------------------------------------------- /09/9-6/9-6-two.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | browser = webdriver.Chrome() 3 | 4 | # 访问指定URL 5 | browser.get('http://www.porters.vip/captcha/mousemove.html') 6 | # 定位页面中的first按钮 7 | hover = browser.find_element_by_class_name('button1') 8 | 9 | action = webdriver.ActionChains(browser) 10 | action.click_and_hold(hover).perform() # 点击并保持不松开 11 | action.move_by_offset(340, 5) # 设置滑动距离,横向距离340px,纵向距离5px 12 | action.release().perform() # 松开鼠标 -------------------------------------------------------------------------------- /09/9-3/9-3-1-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | 4 | browser = webdriver.Chrome() 5 | # 驱动Chrome浏览器打开滑动验证码示例页面 6 | browser.get('http://www.porters.vip/captcha/sliders.html') 7 | # 定位滑块 8 | hover = browser.find_element_by_css_selector('.hover') 9 | 10 | action = webdriver.ActionChains(browser) 11 | action.click_and_hold(hover).perform() # 点击并保持不松开 12 | action.move_by_offset(340, 0) # 设置滑动距离,横向距离340px,纵向距离0px 13 | action.release().perform() # 松开鼠标 -------------------------------------------------------------------------------- /07/7-4/7-4-1-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from parsel import Selector 3 | from urllib.parse import urljoin 4 | 5 | url = 'http://www.porters.vip:8202/' 6 | resp = requests.get(url) 7 | text = Selector(resp.text) 8 | # 提取商品详情的超链接 9 | shops = text.css('.col-md-3 a::attr("href")').extract() 10 | for s in shops: 11 | # 循环商品超链接列表,依次向商品详情页发出请求 12 | detail = urljoin(url, s) 13 | detail_resp = requests.get(detail) 14 | # 打印商品详情页响应正文 15 | print(detail_resp.text) -------------------------------------------------------------------------------- /09/captcha/js/common.js: -------------------------------------------------------------------------------- 1 | var fontSize = 18; // 字体大小 2 | var fonts = fontSize +'px Arial'; 3 | 4 | 5 | function randNumber(min, max){ 6 | // 随机数方法 7 | var res = parseInt(Math.random() * (max - min) + min); 8 | return res; 9 | } 10 | 11 | function randColor(min, max){ 12 | // 随机色方法 13 | var r = randNumber(min, max); var g = randNumber(min, max); var b = randNumber(min, max); 14 | var colorRes = `rgb(${r}, ${b}, ${b})`; 15 | return colorRes; 16 | } -------------------------------------------------------------------------------- /06/6-3/6-3-1-two.py: -------------------------------------------------------------------------------- 1 | # 定义映射关系 2 | mappings = {'vhk08k': 0, 'vhk6zl': 1, 'vhk9or': 2, 3 | 'vhkfln': 3, 'vhkbvu': 4, 'vhk84t': 5, 4 | 'vhkvxd': 6, 'vhkqsc': 7, 'vhkjj4': 8, 5 | 'vhk0f1': 9} 6 | # 商家联系电话class属性 7 | html_d_class = ['vhkbvu', 'vhk08k', 'vhk08k', 8 | '', 'vhk84t', 'vhk6zl', 9 | 'vhkqsc', 'vhkqsc', 'vhk6zl'] 10 | 11 | phone = [mappings.get(i) for i in html_d_class] 12 | # 将映射后的结果打印输出 13 | print(phone) -------------------------------------------------------------------------------- /04/4-1/4-1-1-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from parsel import Selector 3 | 4 | 5 | url = 'http://www.porters.vip/verify/uas/index.html' 6 | # 向目标网址发起网络请求 7 | resp = requests.get(url) 8 | # 打印输出状态码 9 | print(resp.status_code) 10 | # 如果本次请求的状态码为200则继续,否则提示失败 11 | if resp.status_code == 200: 12 | sel = Selector(resp.text) 13 | # 根据HTML标签和属性从响应正文中提取新闻标题 14 | res = sel.css('.list-group-item::text').extract() 15 | print(res) 16 | else: 17 | print('This request is fial.') -------------------------------------------------------------------------------- /04/4-2/4-2-1-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from lxml import etree 3 | 4 | url = 'http://www.porters.vip/verify/cookie/content.html' 5 | # 向目标网址发起网络请求 6 | resp = requests.get(url) 7 | # 打印输出状态码 8 | print(resp.status_code) 9 | # 如果本次请求的状态码为200则继续,否则提示失败 10 | if resp.status_code == 200: 11 | # 将响应正文赋值给html变量 12 | html = etree.HTML(resp.text) 13 | # 根据HTML标签和样式属性从文本中标题的Element对象 14 | res = html.cssselect('.page-header h1') 15 | print(res) 16 | else: 17 | print('This request is fial.') -------------------------------------------------------------------------------- /.idea/antispider.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /07/7-1/7-1-1-two.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyppeteer import launch 3 | 4 | async def main(): 5 | browser = await launch() 6 | page = await browser.newPage() 7 | await page.goto('http://www.porters.vip/features/webdriver.html') 8 | # 定位按钮元素并点击 9 | await page.click('.btn.btn-primary.btn-lg') 10 | # 等待1秒 11 | await asyncio.sleep(1) 12 | # 网页截图保存 13 | await page.screenshot({'path': 'webdriver.png'}) 14 | await browser.close() 15 | 16 | asyncio.get_event_loop().run_until_complete(main()) -------------------------------------------------------------------------------- /05/5-2/5-2-5-two.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyppeteer import launch 3 | 4 | 5 | async def main(): 6 | # 初始化浏览器对象 7 | browser = await launch() 8 | # 在浏览器上下文中创建新页面 9 | page = await browser.newPage() 10 | # 打开目标网址 11 | await page.goto('http://www.ituring.com.cn/') 12 | # 在指定位置输入文本 13 | await page.type('.key', 'Python') 14 | # 截图并保存为ituring.png 15 | await page.screenshot({'path': 'ituring.png'}) 16 | # 关闭浏览器对象 17 | await browser.close() 18 | 19 | asyncio.get_event_loop().run_until_complete(main()) -------------------------------------------------------------------------------- /10/10-1/10-1-5-one.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import AES 2 | # 初始化AES对象时传入密钥,加密模式和iv 3 | aes1 = AES.new('63f09k56nv2b10cf', AES.MODE_CBC, '01pv928nv2i5ss68') 4 | # 待加密消息 5 | message = "Hi!I am from the earth number 77" 6 | print('待加密消息:%s' % message) 7 | # 加密操作 8 | cipher_text = aes1.encrypt(message) 9 | 10 | # 初始化AES对象时传入与加密时相同的密钥,加密模式和iv 11 | aes2 = AES.new('63f09k56nv2b10cf', AES.MODE_CBC, '01pv928nv2i5ss68') 12 | # 解密操作 13 | plaint_text = aes2.decrypt(cipher_text) 14 | print('密文:%s' % cipher_text) 15 | print('明文:%s' % plaint_text.decode('utf8')) -------------------------------------------------------------------------------- /04/4-1/4-1-1-two.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from parsel import Selector 3 | # 使用Postman的身份标识 4 | header = {"User-Agent": "Postman"} 5 | url = 'http://www.porters.vip/verify/uas/index.html' 6 | # 向目标网址发起网络请求,但将客户端身份标识切换为Postman 7 | resp = requests.get(url, headers=header) 8 | # 打印输出状态码 9 | print(resp.status_code) 10 | # 如果本次请求的状态码为200则继续,否则提示失败 11 | if resp.status_code == 200: 12 | sel = Selector(resp.text) 13 | # 根据HTML标签和属性从响应正文中提取新闻标题 14 | res = sel.css('.list-group-item::text').extract() 15 | print(res) 16 | else: 17 | print('This request is fial.') -------------------------------------------------------------------------------- /04/4-2/4-2-1-two.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from lxml import etree 3 | 4 | url = 'http://www.porters.vip/verify/cookie/content.html' 5 | # 向目标网址发起网络请求 6 | header = {"Cookie": "isfirst=789kq7uc1pp4c"} 7 | resp = requests.get(url, headers=header) 8 | # 打印输出状态码 9 | print(resp.status_code) 10 | # 如果本次请求的状态码为200则继续,否则提示失败 11 | if resp.status_code == 200: 12 | # 将响应正文赋值给html变量 13 | html = etree.HTML(resp.text) 14 | # 根据HTML标签和样式属性从文本中标题的Element对象 15 | res = html.cssselect('.page-header h1')[0].text 16 | print(res) 17 | else: 18 | print('This request is fial.') -------------------------------------------------------------------------------- /07/7-1/7-1-3-one.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver import Chrome 2 | import time 3 | 4 | browser = Chrome() 5 | browser.get('http://www.porters.vip/features/webdriver.html') 6 | # 编写修改navigator.webdriver值的JavaScript代码 7 | script = 'Object.defineProperty(navigator, "webdriver", {get: () => false,});' 8 | # 运行JavaScript代码 9 | browser.execute_script(script) 10 | time.sleep(1) 11 | # 定位按钮并点击 12 | browser.find_element_by_css_selector('.btn.btn-primary.btn-lg').click() 13 | # 定位到文章内容元素 14 | elements = browser.find_element_by_css_selector('#content') 15 | time.sleep(1) 16 | # 打印文章内容 17 | print(elements.text) 18 | browser.close() -------------------------------------------------------------------------------- /05/5-2/5-2-2-two.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from pyppeteer import launch 3 | 4 | async def main(): 5 | # 初始化浏览器对象 6 | browser = await launch() 7 | # 在浏览器上下文中创建新页面 8 | page = await browser.newPage() 9 | # 打开目标网址 10 | await page.goto('http://www.porters.vip/verify/sign') 11 | # 点击指定按钮 12 | await page.click('#fetch_button') 13 | # 读取页面指定位置的文本 14 | resp = await page.xpath('//*[@id="content"]') 15 | text = await(await resp[0].getProperty('textContent')).jsonValue() 16 | print(text) 17 | # 关闭浏览器对象 18 | await browser.close() 19 | 20 | asyncio.get_event_loop().run_until_complete(main()) -------------------------------------------------------------------------------- /05/5-2/5-2-3-one.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | # Splash 接口 5 | render = 'http://www.porters.vip:8050/execute' 6 | # 需要执行的命令 7 | script = """ 8 | function main(splash) 9 | splash:go('http://www.porters.vip/verify/sign') 10 | local butt = splash:select('#fetch_button') 11 | butt:mouse_click() 12 | content = splash:select('#content'):text() 13 | return { 14 | results = content 15 | } 16 | end 17 | """ 18 | # 设置请求头 19 | header = {'content-type': 'application/json'} 20 | # 按照Splash规定提交命令 21 | data = json.dumps({"lua_source": script}) 22 | # 向Splash接口发出请求并携带上请求头和命令参数 23 | resp = requests.post(render, data=data, headers=header) 24 | # 打印返回的json 25 | print(resp.json()) -------------------------------------------------------------------------------- /06/6-1/6-1-1-two.py: -------------------------------------------------------------------------------- 1 | import io 2 | import requests 3 | from urllib.parse import urljoin 4 | from parsel import Selector 5 | try: 6 | from PIL import Image 7 | except ImportError: 8 | import Image 9 | import pytesseract 10 | 11 | url = 'http://www.porters.vip/confusion/recruit.html' 12 | resp = requests.get(url) 13 | sel = Selector(resp.text) 14 | # 从响应正文中提取图片名称 15 | image_name = sel.css('.pn::attr("src")').extract_first() 16 | # 拼接图片名和URL 17 | image_url = urljoin(url, image_name) 18 | # 请求图片,拿到图片的字节流内容 19 | image_body = requests.get(image_url).content 20 | # 使用Image.open打开图片字节流,得到图片对象 21 | image_stream = Image.open(io.BytesIO(image_body)) 22 | # 使用光学字符识别从图片对象中读取文字并打印输出结果 23 | print(pytesseract.image_to_string(image_stream)) -------------------------------------------------------------------------------- /09/9-4/9-4-5-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | 3 | 4 | browser = webdriver.Chrome() 5 | # 驱动Chrome浏览器打开滑动验证码示例页面 6 | browser.get('http://www.porters.vip/captcha/jigsawCanvas.html') 7 | 8 | # 定位滑块 9 | jigsawCircle = browser.find_element_by_css_selector('#jigsawCircle') 10 | # 定位背景图片 11 | jigsawCanvas = browser.find_element_by_css_selector('#jigsawCanvas') 12 | jigsawCanvas.screenshot('before.png') 13 | action = webdriver.ActionChains(browser) 14 | # 点击并保持不松开 15 | action.click_and_hold(jigsawCircle).perform() 16 | # 执行js隐藏圆角矩形的HTML代码 17 | scripts = """ 18 | var missblock = document.getElementById('missblock'); 19 | missblock.style['visibility'] = 'hidden'; 20 | """ 21 | browser.execute_script(scripts) 22 | # 再次截图 23 | jigsawCanvas.screenshot('after.png') -------------------------------------------------------------------------------- /09/9-1/9-1-1-three.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PIL import Image 3 | except ImportError: 4 | import Image 5 | import pytesseract 6 | from os import path 7 | 8 | 9 | def handler(grays, threshold=160): 10 | """对灰度图片进行二值化处理 11 | 默认阈值为160,可根据实际情况调整 12 | """ 13 | table = [] 14 | for i in range(256): 15 | if i < threshold: 16 | table.append(0) 17 | else: 18 | table.append(1) 19 | anti = grays.point(table, '1') 20 | return anti 21 | 22 | 23 | # 保存在本地的验证码图片路径 24 | images = path.join(path.dirname(path.abspath(__file__)), 'images/words.png') 25 | # 图片灰度处理 26 | gray = Image.open(images).convert('L') 27 | # 图片二值化处理 28 | image = handler(gray) 29 | image.show() 30 | # 使用pytesseract库识别验证码中的字符并打印 31 | print(pytesseract.image_to_string(image)) -------------------------------------------------------------------------------- /09/9-6/9-6-three.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | browser = webdriver.Chrome() 3 | 4 | # 访问指定URL 5 | browser.get('http://www.porters.vip/captcha/mousemove.html') 6 | # 定位页面中的first按钮 7 | hover = browser.find_element_by_class_name('button1') 8 | 9 | action = webdriver.ActionChains(browser) 10 | action.click_and_hold(hover).perform() # 点击并保持不松开 11 | # 设置滑动距离,横向总距离340px,纵向晃动 12 | action.move_by_offset(100, 3) 13 | action.move_by_offset(40, -5) 14 | action.move_by_offset(10, 3) 15 | action.move_by_offset(5, 2) 16 | action.move_by_offset(10, -1) 17 | action.move_by_offset(30, 3) 18 | action.move_by_offset(55, -2) 19 | action.move_by_offset(10, 1) 20 | action.move_by_offset(30, 3) 21 | action.move_by_offset(20, -1) 22 | action.move_by_offset(10, -4) 23 | action.move_by_offset(10, 2) 24 | action.move_by_offset(10, -6) 25 | action.release().perform() # 松开鼠标 -------------------------------------------------------------------------------- /08/8-2/8-2-2-one.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | from random import randint, sample 3 | import hashlib 4 | import requests 5 | 6 | 7 | def hex5(value): 8 | # 使用 md5 加密值并返回加密后的字符串 9 | manipulator = hashlib.md5() 10 | manipulator.update(value.encode('utf-8')) 11 | return manipulator.hexdigest() 12 | 13 | 14 | # 生成1-9之间的5个随机数字 15 | action = "".join([str(randint(1, 9)) for _ in range(5)]) 16 | # 生成当前时间戳 17 | tim = round(time()) 18 | # 生成5个随机大写字母 19 | randstr = "".join(sample([chr(_) for _ in range(65, 91)], 5)) 20 | # 三个参数拼接后进行md5加密 21 | value = action+str(tim)+randstr 22 | hexs = hex5(value) 23 | 24 | 25 | def uri(): 26 | # 拼接URI 27 | args = '?actions={}&tim={}&randstr={}&sign={}'.format(action, tim, randstr, hexs) 28 | return args 29 | 30 | url = 'http://www.porters.vip:8207/api/v1/detail' + uri() 31 | resp = requests.get(url) 32 | print(resp.status_code, resp.text) -------------------------------------------------------------------------------- /09/9-2/9-2-1-two.py: -------------------------------------------------------------------------------- 1 | try: 2 | from PIL import Image 3 | except ImportError: 4 | import Image 5 | import pytesseract 6 | from os import path 7 | 8 | 9 | # 保存在本地的验证码图片路径 10 | images = path.join(path.dirname(path.abspath(__file__)), 'images/mathes.png') 11 | # 使用pytesseract库识别图中计算题并打印 12 | print(pytesseract.image_to_string(images)) 13 | import re 14 | # 将识别结果复制给 strings 15 | strings = pytesseract.image_to_string(images) 16 | # 从识别结果中提取数字 17 | string = re.findall('\d+', strings) 18 | # 从识别结果中提取运算符 19 | operator = re.findall('[+|\-|\*]', strings) 20 | 21 | def operator_func(a: int, b: int, oper: str) -> int: 22 | # 接收两个值和运算符,返回数学运算结果 23 | if oper == '+': 24 | return a + b 25 | if oper == '-': 26 | return a - b 27 | if oper == '*': 28 | return a * b 29 | 30 | # 将识别结果传入运算方法,获得运算结果 31 | res = operator_func(int(string[0]), int(string[1]), operator[0]) 32 | print(res) -------------------------------------------------------------------------------- /04/4-3/4-3-1-one.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | from random import randint, sample 3 | import hashlib 4 | 5 | 6 | def hex5(value): 7 | # 使用 md5 加密值并返回加密后的字符串 8 | manipulator = hashlib.md5() 9 | manipulator.update(value.encode('utf-8')) 10 | return manipulator.hexdigest() 11 | 12 | 13 | # 生成1-9之间的5个随机数字 14 | action = "".join([str(randint(1, 9)) for _ in range(5)]) 15 | # 生成当前时间戳 16 | tim = round(time()) 17 | # 生成5个随机大写字母 18 | randstr = "".join(sample([chr(_) for _ in range(65, 91)], 5)) 19 | # 三个参数拼接后进行md5加密 20 | value = action+str(tim)+randstr 21 | hexs = hex5(value) 22 | print(action, tim, randstr, hexs) 23 | 24 | 25 | import requests 26 | def uri(): 27 | args = '?actions={}&tim={}&randstr={}&sign={}'.format(action, tim, randstr, hexs) 28 | return args 29 | 30 | url = 'http://www.porters.vip/verify/sign/fet' + uri() 31 | resp = requests.get(url) 32 | print(resp.status_code, resp.text) -------------------------------------------------------------------------------- /10/10-1/private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQCcL0c4oVjmgp0QxA5PMDo2XwIWDFXAPnyuvZ1NFOgCAe3utPOx 3 | aAoXxyRFPlQIZXaRSVNCPxzALLBWpXb+j+j9m3yQBCY4746BA/dxF8zaKt1bkS9Y 4 | VWK+zJGTe9rt0LmcSUJLKJqcui+PRbTLD/xi8rPU4cqHxfZZMQ2WAnnoLwIDAQAB 5 | AoGASk8gNqxljL7GFe0B1eFfQPExH+Zcgiv4zHbAuaThwdrDJpiHfXe/nZKNCjje 6 | aGRF5lgZueInPrPEbmUpWXKE6i4/BkjKrkNHOapBYpWFE0yaGQt63GALq64NcWZa 7 | /lcPEWwv7xMYWgCjEWez4t2BkEidWGNZ//lvRVtKgMn3ahkCQQDAaVLbQqIy4XcV 8 | bfajH0yKtALYWDlslz3jL7hJx85QYSvBpzrhoHNZkJtOYxHwPnrkPOeAUAATTGBO 9 | GmatiNjNAkEAz80L0YAuHZ37XPJILX+5zHwXVPLOdYY8qcLOUMkaYLd53ujHTBSU 10 | vcny92Hs3oRdCG7juE5GWZUBWLeYWhZ06wJAaBQQx52hkxg2jBbxRIdXped9an0+ 11 | gqjExzE25GH6DayiOJw203kxLA92ks4wE94YJ4FyUAv2Hno/1b+eLtxJOQJAZ4jF 12 | Q6u2zmDhVa0Nk0XZP+3v/g5AGcQ5Q2fhPdUFBH1GBm86pUh315vgJ6utxixy4fnG 13 | EhVF7epU0mwfR3t64wJBAIe12MxB+tx1ruD1rxci2lACk8EYYb9UASXJO1r1AmjG 14 | 8gs8787FzngDR2I1EX8TO2MFLCMbqqo3DPD0itVZ4R0= 15 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /06/6-3/6-3-3-one.py: -------------------------------------------------------------------------------- 1 | url_css = 'http://www.porters.vip/confusion/css/food.css' 2 | url_svg = 'http://www.porters.vip/confusion/font/food.svg' 3 | css_class_name = 'vhkbvu' 4 | 5 | import requests 6 | css_resp = requests.get(url_css).text 7 | svg_resp = requests.get(url_svg).text 8 | 9 | import re 10 | pile = '.%s{background:-(\d+)px-(\d+)px;}' % css_class_name 11 | pattern = re.compile(pile) 12 | css = css_resp.replace('\n', '').replace(' ', '') 13 | coord = pattern.findall(css) 14 | if coord: 15 | x, y = coord[0] 16 | x, y = int(x), int(y) 17 | 18 | from parsel import Selector 19 | svg_data = Selector(svg_resp) 20 | texts = svg_data.xpath('//text') 21 | 22 | axis_y = [i.attrib.get('y') for i in texts if y <= int(i.attrib.get('y'))][0] 23 | 24 | svg_text = svg_data.xpath('//text[@y="%s"]/text()' % axis_y).extract_first() 25 | 26 | font_size = re.search('font-size:(\d+)px', svg_resp).group(1) 27 | 28 | position = x // int(font_size) 29 | 30 | number = svg_text[position] 31 | print(number) -------------------------------------------------------------------------------- /09/captcha/css/sliders.css: -------------------------------------------------------------------------------- 1 | /* 滑动验证码 */ 2 | .tracks{ 3 | width: 390px; 4 | height: 40px; 5 | background: #d0c4fe; 6 | overflow: hidden; 7 | border: 1px solid #c5c5c5; 8 | border-radius: 4px; 9 | text-align: center; 10 | } 11 | #sliderblock{ 12 | left:0px; 13 | position: absolute; 14 | color: #fff; 15 | } 16 | 17 | #sliderblock:hover{ 18 | color: #666; 19 | } 20 | 21 | .trackBase{ 22 | width: 390px; 23 | height: 40px; 24 | 25 | position: absolute; 26 | text-align: center; 27 | line-height: 40px; 28 | margin-top: -40px; 29 | } 30 | .hover{ 31 | margin-left: 16px; 32 | width: 50px; 33 | height: 38px; 34 | background: #ad99ff; 35 | text-align: center; 36 | line-height: 38px; 37 | } 38 | .hover:hover{ 39 | background: #fff; 40 | } 41 | 42 | .slidertips { 43 | height: 38px; 44 | line-height: 38px; 45 | color: #fff; 46 | visibility: hidden; 47 | } 48 | 49 | .clientfather { 50 | width: 390px; 51 | } 52 | -------------------------------------------------------------------------------- /09/9-4/9-4-1-one.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | browser = webdriver.Chrome() 3 | # 驱动Chrome浏览器打开滑动验证码示例页面 4 | browser.get('http://www.porters.vip/captcha/jigsaw.html') 5 | # 定位滑块 6 | jigsawCircle = browser.find_element_by_css_selector('#jigsawCircle') 7 | action = webdriver.ActionChains(browser) 8 | # 点击并保持不松开 9 | action.click_and_hold(jigsawCircle).perform() 10 | # 返回当前页面的html代码 11 | html = browser.page_source 12 | 13 | import re 14 | from parsel import Selector 15 | sel = Selector(html) 16 | # 获取圆角矩形和缺口的CSS样式 17 | mbk_style = sel.css('#missblock::attr("style")').get() 18 | tbk_style = sel.css('#targetblock::attr("style")').get() 19 | # 编写用于从CSS样式中提取left属性值的匿名函数 20 | extract = lambda x: ''.join(re.findall('left: (\d+|\d+.\d+)px', x)) 21 | # 调用匿名函数获取CSS样式中的left属性值 22 | mbk_left = extract(mbk_style) 23 | tbk_left = extract(tbk_style) 24 | # 计算当前拼图验证码滑块所需移动的距离 25 | distance = float(tbk_left) - float(mbk_left) 26 | 27 | action.move_by_offset(distance, 0) # 设置滑动距离 28 | action.release().perform() # 松开鼠标 -------------------------------------------------------------------------------- /04/4-2/fet.js: -------------------------------------------------------------------------------- 1 | function randcookie(){ 2 | // 生成随机字符串用作cookie值 3 | var header = randints(9, 3, 0); 4 | var middle = randstrs(5); 5 | var footer = randints(9, 6, 0); 6 | var pp = randstrs(3); 7 | var res = header + middle + footer + pp 8 | return res; 9 | } 10 | 11 | function randints(r, n, tof){ 12 | /* 生成随机数字,tof决定返回number类型或者字符串类型 13 | r 代表数字范围 n 代表数量 14 | */ 15 | 16 | var result = []; 17 | if(tof){ 18 | return Math.floor(Math.random()*r); 19 | } 20 | for(var i=0;i= 0 else False 37 | # 计算下标,以16px为基准 38 | index = int(position / 16) 39 | # 替换第一对b标签值列表中的元素,也就是完成值覆盖操作 40 | base_price[index] = value 41 | print(base_price) -------------------------------------------------------------------------------- /04/4-4/client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import base64 3 | import random 4 | import time 5 | from urllib.parse import urlparse 6 | 7 | 8 | def get_url_info(url): 9 | """解析url""" 10 | url = urlparse(url) 11 | host = url.netloc 12 | resource = url.path or '/' 13 | return host, resource 14 | 15 | 16 | def get_key(): 17 | """生成key""" 18 | bytes_key = bytes(random.getrandbits(8) for _ in range(16)) 19 | res = base64.b64encode(bytes_key).decode() 20 | return res 21 | 22 | 23 | def get_header(url): 24 | """生成握手所需的信息""" 25 | key = get_key() 26 | host, resource = get_url_info(url) 27 | head = {'Connection': 'Upgrade', 'Upgrade': 'websocket', 28 | 'Sec-WebSocket-Version': 13, 'Sec-WebSocket-Key': key, 29 | 'Origin': '{}'.format(host)} 30 | headers = ['{}:{}'.format(k, item) for k, item in head.items()] 31 | headers.insert(0, 'GET {} HTTP/1.1'.format(resource)) 32 | headers.append('\r\n') 33 | header = '\r\n'.join(headers) 34 | return header.encode('utf8') 35 | 36 | 37 | def shake_hands(client, url): 38 | """发起握手并校验握手结果""" 39 | header = get_header(url) 40 | client.send(header) # 发送握手信息 41 | time.sleep(5) 42 | # 读取服务端返回的握手结果 43 | message = client.recv(1024).decode('utf8') 44 | print(message) 45 | if 'Status Code:101' in message: 46 | return True 47 | return False 48 | 49 | 50 | if __name__ == '__main__': 51 | url = 'ws://localhost:50007' 52 | host, resource = get_url_info(url) 53 | # 创建socket连接 54 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 55 | client.connect(('localhost', 50007)) 56 | print(shake_hands(client, url)) 57 | client.close() -------------------------------------------------------------------------------- /07/7-4/hidden.py: -------------------------------------------------------------------------------- 1 | import tornado.ioloop 2 | import tornado.web 3 | import os 4 | 5 | 6 | blacks = set() 7 | 8 | 9 | class MainHandler(tornado.web.RequestHandler): 10 | """首页""" 11 | def get(self): 12 | # 获取客户端ip 13 | client = self.request.remote_ip 14 | # 将该视图与模板文件夹中的details.html文件绑定 15 | self.render("details.html") 16 | class DetailHandler(tornado.web.RequestHandler): 17 | """简单的详情页""" 18 | def get(self): 19 | # 获取客户端IP 20 | client = self.request.remote_ip 21 | if client not in blacks: 22 | # 如果客户端IP不在黑名单则返回数据 23 | params = self.request.arguments # 获取请求正文 24 | phone = params.get('phone')[0].decode('utf-8') 25 | self.finish("%s's data,you get." % phone) 26 | else: 27 | # 将响应状态码设置为403并返回提示信息 28 | self.set_status(403) 29 | self.finish('Got a spider.') 30 | 31 | 32 | class HunterHandler(tornado.web.RequestHandler): 33 | """访问到该接口的客户端IP都加入黑名单""" 34 | def get(self): 35 | # 获取客户端IP 36 | client = self.request.remote_ip 37 | if client not in blacks: 38 | blacks.add(client) 39 | # 将响应状态码设置为403并返回提示信息 40 | self.set_status(403) 41 | self.finish('Got a spider.') 42 | 43 | def make_app(): 44 | # 路由和静态文件路径设置 45 | return tornado.web.Application( 46 | [(r"/", MainHandler), (r"/detail/", DetailHandler), (r"/details/", HunterHandler)], 47 | template_path=os.path.join(os.path.dirname(__file__), 'template'), 48 | static_path=os.path.join(os.path.dirname(__file__), 'static') 49 | ) 50 | 51 | 52 | if __name__ == "__main__": 53 | # 绑定端口并启动 54 | app = make_app() 55 | app.listen(8202) 56 | tornado.ioloop.IOLoop.current().start() -------------------------------------------------------------------------------- /09/captcha/css/jigsaw.css: -------------------------------------------------------------------------------- 1 | 2 | /* 拼图验证码 */ 3 | 4 | .jigsaw { 5 | /* width: 300px; */ 6 | padding: 20px; 7 | background-color: #fff; 8 | box-shadow: 2px 2px 8px 0 rgba(0, 0, 0, 0.4); 9 | } 10 | 11 | .imagebox { 12 | position: relative; 13 | /* width: 300px; */ 14 | overflow: hidden; 15 | box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.4); 16 | } 17 | 18 | .imagebox img { 19 | width: 100%; 20 | } 21 | 22 | .imagebox div { 23 | display: none; 24 | } 25 | 26 | .jigsawTrack { 27 | display: flex; 28 | align-items: center; 29 | position: relative; 30 | height: 30px; 31 | border-radius: 20px; 32 | margin: 20px 0; 33 | padding: 4px 0 4px 70px; 34 | box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2) inset; 35 | background: #f5f5f5; 36 | user-select: none; 37 | } 38 | 39 | .jigsawTips { 40 | opacity: 1; 41 | transition: opacity 0.5s ease-in-out; 42 | color: #aaa; 43 | } 44 | 45 | .jigsawCircle { 46 | position: absolute; 47 | top: -5px; 48 | left: 0px; 49 | width: 45px; 50 | height: 45px; 51 | border-radius: 50%; 52 | background-color: #ae99ff; 53 | box-shadow: 2px 2px 6px 0 rgba(0, 0, 0, 0.2); 54 | } 55 | 56 | .missblock { 57 | position: absolute; 58 | left: 10px; 59 | width: 38px; 60 | height: 38px; 61 | border-radius: 5px; 62 | background-repeat: no-repeat; 63 | background-attachment: scroll; 64 | background-size: 300px; 65 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4), 0 0 10px 0 rgba(90, 90, 90, 0.4); 66 | z-index: 10; 67 | } 68 | 69 | .targetblock { 70 | position: absolute; 71 | width: 38px; 72 | height: 38px; 73 | border-radius: 5px; 74 | background-color: rgba(0, 0, 0, 0.1); 75 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4) inset; 76 | } 77 | -------------------------------------------------------------------------------- /04/4-4/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | 4 | def verify(data): 5 | """验证客户端握手信息""" 6 | data = data[:-4].split('\r\n') 7 | method = data.pop(0) # 取出请求方式和协议 8 | header = {} 9 | # 将列表转为字典 10 | for key, val in enumerate(data): 11 | try: 12 | name, value = val.split(':') 13 | except Exception as exc: 14 | name, host, port = val.split(':') 15 | value = '{}:{}'.format(host, port) 16 | header[name] = value 17 | 18 | # 不满足条件则False 19 | if any(['GET' not in method, 'HTTP/1.1' not in method, 20 | header.get('Connection') != 'Upgrade', 21 | header.get('Upgrade') != 'websocket', 22 | header.get('Sec-WebSocket-Version') != '13', 23 | not header.get('Sec-WebSocket-Key'), 24 | not header.get('Origin')]): 25 | return False 26 | return True 27 | 28 | 29 | def set_response(status): 30 | """设置响应头""" 31 | head = {'Status Code': '101 Web Socket Protocol Handshake', 'Connection': 'Upgrade', 'Upgrade': 'websocket', 32 | 'Sec-WebSocket-Accept': 'T5ar3gbl3rZJcRmEmBT8vxKjdDo='} 33 | if not status: 34 | head = {'Status Code': '403'} 35 | headers = ['{}:{}'.format(k, item) for k, item in head.items()] 36 | headers.append('\r\n') 37 | res = '\r\n'.join(headers) 38 | return res.encode('utf8') 39 | 40 | 41 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 42 | # 使用Python底层接口创建socket 43 | s.bind(('localhost', 50007)) # 绑定地址和端口 44 | s.listen(1) # 只允许同时1个客户端连接 45 | conn, addr = s.accept() # 客户端对象和客户端地址 46 | with conn: 47 | # 读取客户端发送的消息 48 | data = conn.recv(1024).decode('utf8') 49 | print(data) 50 | status = verify(data) # 校验握手信息 51 | resp = set_response(status) # 根据握手校验结果返回响应头 52 | conn.send(resp) 53 | conn.close() -------------------------------------------------------------------------------- /09/captcha/css/jigsawCanvas.css: -------------------------------------------------------------------------------- 1 | 2 | /* 拼图验证码 */ 3 | 4 | .jigsaw { 5 | width: 420px; 6 | padding: 20px; 7 | background-color: #fff; 8 | box-shadow: 2px 2px 8px 0 rgba(0, 0, 0, 0.4); 9 | } 10 | 11 | .imagebox { 12 | position: relative; 13 | width: 380px; 14 | overflow: hidden; 15 | box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.4); 16 | height: 287px; 17 | } 18 | 19 | .imagebox img { 20 | width: 100%; 21 | } 22 | 23 | .imagebox div { 24 | display: none; 25 | } 26 | 27 | .jigsawTrack { 28 | display: flex; 29 | align-items: center; 30 | position: relative; 31 | height: 30px; 32 | border-radius: 20px; 33 | margin: 20px 0; 34 | padding: 4px 0 4px 70px; 35 | box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2) inset; 36 | background: #f5f5f5; 37 | user-select: none; 38 | } 39 | 40 | .jigsawTips { 41 | opacity: 1; 42 | transition: opacity 0.5s ease-in-out; 43 | color: #aaa; 44 | } 45 | 46 | .jigsawCircle { 47 | position: absolute; 48 | top: -5px; 49 | left: 0px; 50 | width: 45px; 51 | height: 45px; 52 | border-radius: 50%; 53 | background-color: #ae99ff; 54 | box-shadow: 2px 2px 6px 0 rgba(0, 0, 0, 0.2); 55 | } 56 | 57 | .missblock { 58 | position: absolute; 59 | left: 10px; 60 | width: 38px; 61 | height: 38px; 62 | border-radius: 5px; 63 | background-repeat: no-repeat; 64 | background-attachment: scroll; 65 | background-size: 300px; 66 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4), 0 0 10px 0 rgba(90, 90, 90, 0.4); 67 | z-index: 10; 68 | background-image: url(../images/0.jpg); 69 | } 70 | 71 | .targetblock { 72 | position: absolute; 73 | width: 38px; 74 | height: 38px; 75 | border-radius: 5px; 76 | background-color: rgba(0, 0, 0, 0.1); 77 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4) inset; 78 | } 79 | -------------------------------------------------------------------------------- /09/captcha/js/words.js: -------------------------------------------------------------------------------- 1 | /* 静态图片验证码 2 | 验证逻辑:记录程序生成的随机字符 3 | 1、获取用户输入的内容 4 | 2、将用户输入内容关于随机字符比对 5 | 相同则通过验证 6 | */ 7 | 8 | var strs = []; // Canvas 生成的验证码 9 | var fontSize = randNumber(28, 40); // 字体大小 10 | var fonts = fontSize +'px Arial'; 11 | 12 | 13 | function cvasInterfere(cvas, width, height){ 14 | // 浅色干扰线 15 | for(var i=0;i<3;i++){ 16 | cvas.beginPath(); 17 | cvas.moveTo(randNumber(0, width),randNumber(0, height)); 18 | cvas.lineTo(randNumber(0, width),randNumber(0, height)); 19 | cvas.strokeStyle=randColor(180, 260); 20 | cvas.closePath(); 21 | cvas.stroke(); 22 | } 23 | // 浅色干扰噪点 24 | for(var i=0;i<80;i++){ 25 | cvas.beginPath(); 26 | cvas.arc(randNumber(0, width),randNumber(0, height), 1, 0, 2 * Math.PI); 27 | cvas.closePath(); 28 | cvas.fillStyle=randColor(150, 260); 29 | cvas.fill(); 30 | } 31 | } 32 | 33 | 34 | $(function(){ 35 | var wordsCanvas = document.getElementById('wordsCanvas'); 36 | var cvas = wordsCanvas.getContext('2d'); 37 | var letter = "ABCDEFGHJKLIMNPQRSTUVWSYZ1234567890"; 38 | var width = wordsCanvas.width; var height = wordsCanvas.height; 39 | // 绘制底色 40 | cvas.fillStyle = randColor(120, 230); 41 | cvas.fillRect(0, 0, width, height); 42 | for(var i=0;i<6;i++){ 43 | var single = letter[randNumber(0, letter.length)]; // 从字符集中随机取字 44 | cvas.font = fonts; 45 | cvas.textBaseline = 'top'; 46 | cvas.fillStyle=randColor(80, 180); 47 | cvas.save(); 48 | cvas.translate( 30 * i + 15 , 15); 49 | cvas.fillText(single, -15 + 5, -15); 50 | cvas.restore(); 51 | strs.push(single) 52 | } 53 | 54 | // 为验证码加上浅色干扰线和噪点 55 | cvasInterfere(cvas, width, height) 56 | }) 57 | 58 | function verifys(){ 59 | // 静态图片验证码用户输入结果 60 | var codeStr = strs.join('').toLowerCase(); 61 | var inputCode = document.getElementById('code').value.toLowerCase(); 62 | if(inputCode==codeStr){ 63 | alert('验证码:' + inputCode + ',通过验证。'); 64 | }else{ 65 | alert('很遗憾,未通过验证'); 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /09/captcha/js/mathes.js: -------------------------------------------------------------------------------- 1 | /* 计算型验证码 2 | 验证逻辑:记录数值与运算符 3 | 1、获取用户输入的数值 4 | 2、将用户输入数值与程序得到的数值比对,相同则通过验证 5 | */ 6 | 7 | function multMath(){ 8 | // 乘法 9 | var first = randNumber(1, 20); 10 | var second = randNumber(5, 15); 11 | return [first, second, '*'] 12 | } 13 | 14 | function additionMath(){ 15 | // 加法 16 | var first = randNumber(20, 99); 17 | var second = randNumber(3, 99); 18 | return [first, second, '+'] 19 | } 20 | 21 | function subMath(){ 22 | // 减法 23 | var first = randNumber(46, 99); 24 | var second = randNumber(1, 45); 25 | return [first, second, '-'] 26 | } 27 | 28 | var mathesResult = []; // Canvas 生成的验证码 29 | 30 | $(function(){ 31 | var matchesCanvas = document.getElementById('matchesCanvas'); 32 | var cvas = matchesCanvas.getContext('2d'); 33 | // 获取计算题目 34 | var mathList = [multMath(), additionMath(), subMath()]; 35 | var i = (randNumber(0, mathList.length)); 36 | var maths = mathList[i] 37 | 38 | var width = matchesCanvas.width - 20; var height = matchesCanvas.height; 39 | // 先绘制背景色 40 | cvas.fillStyle = `#CDC8B1`; 41 | cvas.fillRect(0, 0, width, height) 42 | 43 | // 再绘制计算题目 44 | cvas.fillStyle = `#7F7F7F`; 45 | var fontSize = 26; 46 | cvas.font = fontSize +'px Arial'; 47 | cvas.textBaseline = 'middle'; 48 | cvas.fillText(maths[0], 10, 20); 49 | cvas.fillText(maths[2], 50, 20); 50 | cvas.fillText(maths[1], 80, 20); 51 | cvas.fillText('= ?', 120, 20); 52 | if(i == 0){ 53 | var result = parseInt(maths[0]) * parseInt(maths[1]); 54 | }else if(i == 1){ 55 | var result = parseInt(maths[0]) + parseInt(maths[1]); 56 | }else{ 57 | var result = parseInt(maths[0]) - parseInt(maths[1]); 58 | } 59 | // 给出计算结果 60 | mathesResult.push(result); 61 | }) 62 | 63 | 64 | function mathesVerify(){ 65 | // 计算型验证码用户输入结果 66 | var codeInt = parseInt(mathesResult.join('')); 67 | var inputCode = parseInt(document.getElementById('code').value); 68 | if(inputCode==codeInt){ 69 | alert('计算结果:' + inputCode + ',通过验证。'); 70 | }else{ 71 | alert('很遗憾,未通过验证'); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /04/4-5/client.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import base64 3 | import random 4 | import time 5 | from urllib.parse import urlparse 6 | import json 7 | 8 | 9 | def get_url_info(url): 10 | """解析url""" 11 | url = urlparse(url) 12 | host = url.netloc 13 | resource = url.path or '/' 14 | return host, resource 15 | 16 | 17 | def get_key(): 18 | """生成key""" 19 | bytes_key = bytes(random.getrandbits(8) for _ in range(16)) 20 | res = base64.b64encode(bytes_key).decode() 21 | return res 22 | 23 | 24 | def get_header(url): 25 | """生成握手所需的信息""" 26 | key = get_key() 27 | host, resource = get_url_info(url) 28 | head = {'Connection': 'Upgrade', 'Upgrade': 'websocket', 29 | 'Sec-WebSocket-Version': 13, 'Sec-WebSocket-Key': key, 30 | 'Origin': '{}'.format(host)} 31 | headers = ['{}:{}'.format(k, item) for k, item in head.items()] 32 | headers.insert(0, 'GET {} HTTP/1.1'.format(resource)) 33 | headers.append('\r\n') 34 | header = '\r\n'.join(headers) 35 | return header.encode('utf8') 36 | 37 | 38 | def shake_hands(client, url): 39 | """发起握手并校验握手结果""" 40 | header = get_header(url) 41 | client.send(header) # 发送握手信息 42 | time.sleep(5) 43 | # 读取服务端返回的握手结果 44 | message = client.recv(1024).decode('utf8') 45 | print(message) 46 | if 'Status Code:101' in message: 47 | return True 48 | return False 49 | 50 | 51 | def receive_forever(client): 52 | """读取服务端返回的握手结果""" 53 | while True: 54 | time.sleep(5) 55 | message = client.recv(1024).decode('utf8') 56 | if message: 57 | print(message) 58 | 59 | 60 | def send_message(client, message): 61 | """向服务端发送消息""" 62 | if isinstance(message, str): 63 | message = message.encode('utf8') 64 | if isinstance(message, bytes): 65 | client.send(message) 66 | 67 | 68 | if __name__ == '__main__': 69 | url = 'ws://localhost:50007' 70 | host, resource = get_url_info(url) 71 | # 创建socket连接 72 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 73 | client.connect(('localhost', 50007)) 74 | shake_hands_status = shake_hands(client, url) 75 | message = json.dumps({'method': 'GET', 'content': 'huawei'}) # 消息 76 | send_message(client, message) 77 | receive_forever(client) 78 | client.close() -------------------------------------------------------------------------------- /09/captcha/js/sliders.js: -------------------------------------------------------------------------------- 1 | /* 滑动验证码 2 | 验证逻辑:滑块释放位置-滑块起始位置-滑轨长度等于滑块宽度,允许误差3 3 | 如果值在范围内则通过验证 4 | */ 5 | $(function(){ 6 | 7 | var tracks = document.getElementById('tracks'), 8 | sliderblock = document.getElementById('sliderblock'), 9 | slidertips = document.getElementById('slidertips') 10 | // 滑块宽度 11 | var sliderblockWidth = $('#sliderblock').width(); 12 | // 滑轨长度 13 | var tracksWidth = $('#tracks').width(); 14 | 15 | var mousemove = false; // mousedown状态 16 | sliderblock.addEventListener('mousedown', function (e) { 17 | // 监听mousedown事件,记录滑块起始位置 18 | mousemove = true; // 鼠标按下时,mousedown 状态改变 19 | startCoordinateX = e.clientX // 滑块起始位置 20 | }); 21 | 22 | 23 | var distanceCoordianteX = 0; // 滑块起始位置 24 | tracks.addEventListener('mousemove', function (e) { 25 | //监听鼠标移动 26 | if (mousemove) {// 鼠标点击滑块后才跟踪移动 27 | distanceCoordianteX = e.clientX - startCoordinateX; // 滑块当前位置 28 | if (distanceCoordianteX > tracksWidth - sliderblockWidth) { 29 | // 通过限制滑块位移距离,避免滑块向右移出滑轨 30 | distanceCoordianteX = tracksWidth - sliderblockWidth; 31 | } else if (distanceCoordianteX < 0) { 32 | // 通过限制滑块位移距离,避免滑块向左移出滑轨 33 | distanceCoordianteX = 0; 34 | } 35 | // 根据移动距离显示滑块位置 36 | sliderblock.style.left = distanceCoordianteX + 'px'; 37 | } 38 | }) 39 | 40 | sliderblock.addEventListener('mouseup', function (e){ 41 | // 鼠标松开视为完成滑动,记录滑块当前位置并调用验证方法 42 | var endCoordinateX = e.clientX; 43 | verifySliderRetuls(endCoordinateX); 44 | }) 45 | 46 | function verifySliderRetuls(endCoordinateX){// 验证滑动结果 47 | mousemove = false; // 此时鼠标已松开,防止滑块跟随鼠标移动 48 | // 允许误差3像素。 49 | if (Math.abs(endCoordinateX - startCoordinateX - tracksWidth) < sliderblockWidth + 3) { 50 | // 验证通过后设置提示样式 51 | sliderblock.style.color = '#666'; 52 | sliderblock.style.fontSize = '28px'; 53 | sliderblock.style.backgroundColor = '#fff'; 54 | sliderblock.innerHTML = '✓'; 55 | slidertips.style['visibility'] = 'visible'; 56 | console.log('验证成功'); 57 | } else { 58 | // 如果验证失败,滑块复位 59 | distanceCoordianteX = 0; 60 | sliderblock.style.left = 0; 61 | console.log('验证失败'); 62 | } 63 | } 64 | }) 65 | -------------------------------------------------------------------------------- /06/6-4/6-4-2-two.py: -------------------------------------------------------------------------------- 1 | base_font = { 2 | "font": [{"name": "uniEE76", "value": "0", "hex": "fc170db1563e66547e9100cf7784951f"}, 3 | {"name": "uniF57B", "value": "1", "hex": "251357942c5160a003eec31c68a06f64"}, 4 | {"name": "uniE7DF", "value": "2", "hex": "8a3ab2e9ca7db2b13ce198521010bde4"}, 5 | {"name": "uniF19A", "value": "3", "hex": "712e4b5abd0ba2b09aff19be89e75146"}, 6 | {"name": "uniF593", "value": "4", "hex": "e5764c45cf9de7f0a4ada6b0370b81a1"}, 7 | {"name": "uniEA16", "value": "5", "hex": "c631abb5e408146eb1a17db4113f878f"}, 8 | {"name": "uniE339", "value": "6", "hex": "0833d3b4f61f02258217421b4e4bde24"}, 9 | {"name": "uniE9C7", "value": "7", "hex": "4aa5ac9a6741107dca4c5dd05176ec4c"}, 10 | {"name": "uniEFD4", "value": "8", "hex": "c37e95c05e0dd147b47f3cb1e5ac60d7"}, 11 | {"name": "uniE624", "value": "9", "hex": "704362b6e0feb6cd0b1303f10c000f95"}] 12 | } 13 | 14 | import requests 15 | import re 16 | from parsel import Selector 17 | from urllib import parse 18 | from fontTools.ttLib import TTFont 19 | 20 | 21 | url = 'http://www.porters.vip/confusion/movie.html' 22 | resp = requests.get(url) 23 | sel = Selector(resp.text) 24 | # 提取页面加载的所有css文件路径 25 | css_path = sel.css('link[rel=stylesheet]::attr(href)').extract() 26 | woffs = [] 27 | for c in css_path: 28 | # 拼接正确的css文件路径 29 | css_url = parse.urljoin(url, c) 30 | # 向css文件发起请求 31 | css_resp = requests.get(css_url) 32 | # 匹配css文件中的woff文件路径 33 | woff_path = re.findall("src:url\('..(.*.woff)'\) format\('woff'\);", css_resp.text) 34 | if woff_path: 35 | # 如故路径存在则添加到woffs列表中 36 | woffs += woff_path 37 | 38 | woff_url = 'http://www.porters.vip/confusion' + woffs.pop() 39 | woff = requests.get(woff_url) 40 | filename = 'target.woff' 41 | with open(filename, 'wb') as f: 42 | # 将文件保存到本地 43 | f.write(woff.content) 44 | # 使用TTFont库打开刚才下载的woff文件 45 | font = TTFont(filename) 46 | 47 | web_code = '.' 48 | # 编码文字替换 49 | woff_code = [i.upper().replace('&#X', 'uni') for i in web_code.split('.')] 50 | import hashlib 51 | result = [] 52 | for w in woff_code: 53 | # 从字体文件中取出对应编码的字形信息 54 | content = font['glyf'].glyphs.get(w).data 55 | # 字形信息md5 56 | glyph = hashlib.md5(content).hexdigest() 57 | for b in base_font.get('font'): 58 | # 与基准字形中的md5值进行对比,如果相同则取出该字形描述的文字 59 | if b.get('hex') == glyph: 60 | result.append(b.get('value')) 61 | break 62 | # 打印映射结果 63 | print(result) -------------------------------------------------------------------------------- /04/4-3/4-3-2/4-3-2-one.py: -------------------------------------------------------------------------------- 1 | import tornado.ioloop 2 | import tornado.web 3 | import hashlib 4 | import os 5 | from datetime import datetime 6 | from time import time 7 | 8 | 9 | class MainHandler(tornado.web.RequestHandler): 10 | def get(self): 11 | # 返回页面的视图 12 | self.render("index.html") 13 | 14 | class FetHandler(tornado.web.RequestHandler): 15 | # 定义返回内容 16 | content = """ 17 |

参团的游客,应听从领队、导游人员的安全提醒,切莫擅自行动。 18 | 自身的人身、财物安全要注意,购买人身意外险,贵重物品要随身携带, 19 | 不要留在车内或者交由他人保管。参加漂流、摩天轮等高风险项目的时候, 20 | 要认真听从工作人员的安排,切莫求刺激而发生意外。

21 |

以下是本次参团出行需要遵守的规范要求:

22 |

一、跟刺激相比,命更重要,没有命就什么都没了。

23 |

二、旅行中会遇到很多你从未见过的植物和动物,不要轻易打扰它们,有可能有毒。

24 |

三、身体感觉不适,尤其是发烧、乏力和呕吐等情况必须报告随队医护人员。

25 |

四、出发前请跟家人沟通好,避免造成失联错觉。

26 |

五、出发前请按照队长的要求准备好必备衣物和干粮,最重要的是水。

27 |

六、旅行途中必须紧跟队伍,不许在无人知晓的情况下行动。

28 |

七、如不慎走失,请先释放信号弹,半小时后无人联系再想办法报警。

29 |

八、如果不同意以上几条,请在出发前告知队长。

30 |

九、最重要的是:没有命,就什么都没了。

31 | """ 32 | @staticmethod 33 | def deltas(tp): 34 | # 将前端传递的时间戳与当前时间戳对比并返回差值秒数 35 | tamp = int(tp) 36 | now = round(time()) 37 | delta = datetime.fromtimestamp(now) - datetime.fromtimestamp(tamp) 38 | return delta.total_seconds() 39 | 40 | @staticmethod 41 | def hex5(value): 42 | # 使用 md5 加密值并返回加密后的字符串 43 | manipulator = hashlib.md5() 44 | manipulator.update(value.encode('utf-8')) 45 | return manipulator.hexdigest() 46 | 47 | def comparison(self, actions, tim, randstr, sign): 48 | # 根据传递的参数计算md5值,并与客户端提交的md5值进行比对 49 | value = actions+tim+randstr 50 | hexs = self.hex5(value) 51 | if sign == hexs: 52 | return True 53 | return False 54 | 55 | def get(self): 56 | # 返回数据的视图 57 | params = self.request.arguments # 获取请求正文 58 | actions = params.get('actions')[0].decode('utf-8') 59 | tim = params.get('tim')[0].decode('utf-8') 60 | randstr = params.get('randstr')[0].decode('utf-8') 61 | sign = params.get('sign')[0].decode('utf-8') 62 | seconds = self.deltas(tim) # 取双端时间差值 63 | if self.comparison(actions, tim, randstr, sign) and seconds < 5: 64 | # 如果双端 MD5 值和时间戳差值都符合要求则返回正常内容 65 | self.write(self.content) 66 | else: 67 | self.set_status(403) 68 | 69 | 70 | def make_app(): 71 | # 路由和静态文件路径设置 72 | return tornado.web.Application( 73 | [(r"/", MainHandler), (r"/fet", FetHandler)], 74 | template_path=os.path.join(os.path.dirname(__file__), 'template'), 75 | static_path=os.path.join(os.path.dirname(__file__), 'static') 76 | ) 77 | 78 | 79 | if __name__ == "__main__": 80 | # 绑定端口并启动 81 | app = make_app() 82 | app.listen(8206) 83 | tornado.ioloop.IOLoop.current().start() -------------------------------------------------------------------------------- /04/4-5/server.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import json 3 | 4 | 5 | def verify(data): 6 | """验证客户端握手信息""" 7 | data = data[:-4].split('\r\n') 8 | method = data.pop(0) # 取出请求方式和协议 9 | header = {} 10 | # 将列表转为字典 11 | for key, val in enumerate(data): 12 | try: 13 | name, value = val.split(':') 14 | except Exception as exc: 15 | name, host, port = val.split(':') 16 | value = '{}:{}'.format(host, port) 17 | header[name] = value 18 | 19 | # 不满足条件则False 20 | if any(['GET' not in method, 'HTTP/1.1' not in method, 21 | header.get('Connection') != 'Upgrade', 22 | header.get('Upgrade') != 'websocket', 23 | header.get('Sec-WebSocket-Version') != '13', 24 | not header.get('Sec-WebSocket-Key'), 25 | not header.get('Origin')]): 26 | return False 27 | return True 28 | 29 | 30 | def set_response(status): 31 | """设置响应头""" 32 | head = {'Status Code': '101 Web Socket Protocol Handshake', 'Connection': 'Upgrade', 'Upgrade': 'websocket', 33 | 'Sec-WebSocket-Accept': 'T5ar3gbl3rZJcRmEmBT8vxKjdDo='} 34 | if not status: 35 | head = {'Status Code': '403'} 36 | headers = ['{}:{}'.format(k, item) for k, item in head.items()] 37 | headers.append('\r\n') 38 | res = '\r\n'.join(headers) 39 | return res.encode('utf8') 40 | 41 | 42 | def verify_sting(conn): 43 | """读取客户端发送的消息并进行简单验证""" 44 | methods = ['GET', 'POST'] 45 | while True: 46 | message = conn.recv(1024) 47 | if message: 48 | break 49 | message = json.loads(message) 50 | method = message.get('method') 51 | content = message.get('content') 52 | if method in methods: 53 | return content 54 | shake_hands_status = False # 设置握手成功的状态,默认False 55 | 56 | 57 | def get_data(content): 58 | data = {'huawei': '{"title": "Huawei latest flagship mobile P30 Pro", "price": 3999, "RAM": "8G", "ROM": "256G", "pixel": "4000W"}', 59 | 'iphone': 'iOS'} 60 | return data.get(content) 61 | 62 | 63 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 64 | # 使用Python底层接口创建socket 65 | s.bind(('localhost', 50007)) # 绑定地址和端口 66 | s.listen(1) # 只允许同时1个客户端连接 67 | conn, addr = s.accept() # 客户端对象和客户端地址 68 | shake_hands_status = False # 设置握手成功的状态,默认False 69 | with conn: 70 | # 读取客户端发送的消息 71 | data = conn.recv(1024).decode('utf8') 72 | if not shake_hands_status: 73 | # 避免重复握手 74 | status = verify(data) # 校验握手信息 75 | resp = set_response(status) # 根据握手校验结果返回响应头 76 | conn.send(resp) 77 | shake_hands_status = True # 握手成功后对应状态 78 | 79 | # 以下为客户端消息校验和数据推送 80 | content = verify_sting(conn) 81 | if content: 82 | # 如果客户端消息通过校验则从数据从库中取出对应数据并推送给客户端 83 | data = get_data(content) 84 | conn.send(data.encode('utf8')) -------------------------------------------------------------------------------- /09/captcha/js/jigsaw.js: -------------------------------------------------------------------------------- 1 | /* 拼图验证码 2 | 验证逻辑: 3 | 1、记录缺口位置 4 | 2、在鼠标按下和松开时记录鼠标的相对位置 5 | 3、鼠标松开时的位置与按下时的位置差值与缺口位置比较,在范围内则认为通过 6 | */ 7 | 8 | 9 | var jigsaw = $('.jigsaw'), jigsawTrack = $('.jigsawTrack'), 10 | jigsawCircle = $('.jigsawCircle'), jigsawTips = $('.jigsawTips'), 11 | missblock = $('.missblock'), targetblock = $('.targetblock') 12 | 13 | $(function() { 14 | var imageback = $('.imageback') // 背景图所在标签 15 | imageback.attr('src', `images/1.jpg`) // 背景图 16 | missblock.css('background-image', `url('images/0.jpg')`) // 对应的滑块 17 | var imageback = document.getElementById('imageback'); 18 | imageback.onload = function() { 19 | // 获取图片高度 20 | var imageHeight = this.clientHeight 21 | // 生成缺口坐标 22 | var CoordinateX = 150/2 * (1 + Math.random()), CoordinateY = Math.random() * imageHeight / 2 23 | // 鼠标按下 24 | fnDown(CoordinateX , CoordinateY) 25 | 26 | } 27 | }) 28 | 29 | function fnDown(CoordinateX, CoordinateY) { 30 | jigsawCircle.mousedown(function(e) { 31 | e.stopPropagation() 32 | // 鼠标按下时,显示圆角矩形的位置 33 | var missblockFirst = 10; 34 | missblock.css('left', `${missblockFirst}px`) 35 | // 鼠标按下时,滑块的位置 36 | var circleMousedown = jigsawCircle.offset().left 37 | var missblockWidth = missblock.width(); 38 | var missblockWidthHalf = missblockWidth/2; 39 | // 缺块显示 40 | missblock.css({ 41 | display: 'block', 42 | top: `${CoordinateY}px`, 43 | 'background-position': `-${CoordinateX - missblockWidth/3}px -${CoordinateY - missblockWidth/2}px` 44 | }) 45 | // 缺口位置显示 46 | targetblock.css({ display: 'block', left: `${CoordinateX}px`, top: `${CoordinateY}px` }) 47 | var distanceX = e.clientX - $(this).offset().left; 48 | // 提示文字设为透明 49 | jigsawTips.css('opacity', '0') 50 | 51 | // 监听鼠标移动事件 52 | jigsaw.bind('mousemove', function(e) { 53 | fnMove(e, distanceX) 54 | }) 55 | 56 | // 监听mouseup,根据滑块位置判断结果 57 | jigsaw.bind('mouseup', function() { 58 | var circleMouseup = jigsawCircle.offset().left; 59 | var verifyPosition = circleMouseup - circleMousedown 60 | console.log('缺口位置:' + CoordinateX) 61 | console.log('circle Mouseup:' + circleMouseup + '-减去-' + 'circle Mousedown:' + circleMousedown) 62 | // 误差在2px以内则算成功 63 | if (Math.abs(verifyPosition - CoordinateX + 10) > 2) { 64 | console.log('验证失败') 65 | // 缺块和滑块归位 66 | jigsawCircle.css('left', '0px'); 67 | missblock.css('left', '10px'); 68 | // 显示提示文字 69 | jigsawTips.css('opacity', '1'); 70 | 71 | } else { 72 | alert('您已完成拼图,通过验证'); 73 | } 74 | // 移除鼠标事件监听 75 | jigsaw.unbind('mousemove') 76 | jigsaw.unbind('mouseup') 77 | }) 78 | }) 79 | } 80 | 81 | function fnMove(e, distanceX) { 82 | // 滑块移动范围控制在滑轨中,不可超出 83 | var l = e.clientX - distanceX - $(jigsawTrack).offset().left, winW = $(jigsawTrack).width() + 29 84 | if (l < 0) {l = 0} else if (l > winW) {l = winW} 85 | jigsawCircle.css('left', `${l}px`) 86 | missblock.css('left', `${l + 10}px`) 87 | } -------------------------------------------------------------------------------- /09/captcha/js/jigsawCanvas.js: -------------------------------------------------------------------------------- 1 | /* Canvas 拼图 */ 2 | 3 | var jigsaw = $('.jigsaw'), jigsawTrack = $('.jigsawTrack'), 4 | jigsawCircle = $('.jigsawCircle'), jigsawTips = $('.jigsawTips'), 5 | missblock = $('.missblock'), targetblock = $('.targetblock') 6 | 7 | var missblockFirst = 10; 8 | 9 | $(function() { 10 | var jigsawCanvas = document.getElementById('jigsawCanvas'); 11 | var cvas = jigsawCanvas.getContext('2d'); 12 | var jigsawImages = new Image(); 13 | jigsawImages.src = 'images/2.jpg' 14 | 15 | jigsawImages.onload = function start() { 16 | // 图片加载后将图片绘制到Canvas画布 17 | var imageHeight = jigsawCanvas.height; 18 | var imageWidth = jigsawCanvas.width; 19 | cvas.drawImage(jigsawImages, 0, 0, imageWidth, imageHeight); 20 | cvas.save(); 21 | // 根据背景图标签的宽高生成缺口坐标 22 | var CoordinateX = imageWidth/5 + imageWidth/2 * Math.random(), CoordinateY = imageHeight / 2 * Math.random() 23 | mouseDowns(CoordinateX , CoordinateY) 24 | } 25 | 26 | function mouseDowns(CoordinateX, CoordinateY) { 27 | var targetblockTimes = 0; 28 | jigsawCircle.mousedown(function(e) { 29 | e.stopPropagation() 30 | // 鼠标按下时,滑块的位置 31 | var circleMousedown = jigsawCircle.offset().left; 32 | // 圆角矩形显示 33 | missblock.css({ 34 | display: 'block', 35 | top: `${CoordinateY}px`, 36 | 'background-position': `-${missblockFirst}px -${CoordinateY}px` 37 | }) 38 | // 绘制缺口,计数避免重复绘制 39 | if(targetblockTimes<1){ 40 | var targetImage = new Image(); 41 | targetImage.src = 'images/1.jpg'; 42 | cvas.fillStyle = "rgba(0,0,0,0.6)"; 43 | // 在指定位置绘制38x38大小的矩形 44 | cvas.fillRect(CoordinateX, CoordinateY, 38, 38); 45 | targetblockTimes += 1; 46 | }else{ 47 | console.log('missblock alredy in canvas') 48 | } 49 | // 获取鼠标到按钮的距离 50 | var disX = e.clientX - $(this).offset().left; 51 | // 提示文字设为透明 52 | jigsawTips.css('opacity', '0') 53 | // 监听鼠标移动事件 54 | jigsaw.bind('mousemove', function(e) { 55 | mouseMoves(e, disX) 56 | }) 57 | 58 | // 监听mouseup,根据滑块位置判断结果 59 | jigsaw.bind('mouseup', function() { 60 | // 滑块移动距离等于鼠标松开时的X坐标减去鼠标按下时的X坐标 61 | var circleMouseup = jigsawCircle.offset().left; 62 | var endPosition = circleMouseup - circleMousedown; 63 | // 误差在2px以内则算成功 64 | if (Math.abs(endPosition - CoordinateX + missblockFirst) > 2) { 65 | console.log('验证失败') 66 | // 缺块和滑块归位 67 | jigsawCircle.css('left', '0px'); 68 | missblock.css('left', '10px'); 69 | // 显示提示文字 70 | jigsawTips.css('opacity', '1'); 71 | } else { 72 | alert('您已完成拼图,通过验证'); 73 | } 74 | // 移除鼠标事件监听 75 | jigsaw.unbind('mousemove') 76 | jigsaw.unbind('mouseup') 77 | }) 78 | }) 79 | } 80 | }) 81 | 82 | function mouseMoves(e, distanceX) { 83 | // 滑块移动范围控制在滑轨中,不可超出 84 | var jigsawCirclePosition = e.clientX - distanceX - $(jigsawTrack).offset().left; 85 | var jigsawTrackWidth = jigsawTrack.width(); // 滑轨长度 86 | if (jigsawCirclePosition < 0) { 87 | jigsawCirclePosition = 0 88 | }else if (jigsawCirclePosition > jigsawTrackWidth) { 89 | jigsawCirclePosition = jigsawTrackWidth 90 | } 91 | //实时显示滑块和圆角矩形的位置 92 | jigsawCircle.css('left', `${jigsawCirclePosition}px`) 93 | missblock.css('left', `${jigsawCirclePosition + missblockFirst}px`) 94 | } -------------------------------------------------------------------------------- /09/captcha/jigsawCanvas.js: -------------------------------------------------------------------------------- 1 | /* Canvas 拼图 */ 2 | 3 | var jigsaw = $('.jigsaw'), jigsawTrack = $('.jigsawTrack'), 4 | jigsawCircle = $('.jigsawCircle'), jigsawTips = $('.jigsawTips'), 5 | missblock = $('.missblock'), targetblock = $('.targetblock') 6 | 7 | var missblockFirst = 10; 8 | 9 | $(function() { 10 | var jigsawCanvas = document.getElementById('jigsawCanvas'); 11 | var cvas = jigsawCanvas.getContext('2d'); 12 | var jigsawImages = new Image(); 13 | jigsawImages.src = 'images/2.jpg' 14 | 15 | jigsawImages.onload = function start() { 16 | // 图片加载后将图片绘制到Canvas画布 17 | var imageHeight = jigsawCanvas.height; 18 | var imageWidth = jigsawCanvas.width; 19 | cvas.drawImage(jigsawImages, 0, 0, imageWidth, imageHeight); 20 | cvas.save(); 21 | // 根据背景图标签的宽高生成缺口坐标 22 | var CoordinateX = imageWidth/5 + imageWidth/2 * Math.random(), CoordinateY = imageHeight / 2 * Math.random() 23 | mouseDowns(CoordinateX , CoordinateY) 24 | } 25 | 26 | function mouseDowns(CoordinateX, CoordinateY) { 27 | var targetblockTimes = 0; 28 | jigsawCircle.mousedown(function(e) { 29 | e.stopPropagation() 30 | // 鼠标按下时,滑块的位置 31 | var circleMousedown = jigsawCircle.offset().left; 32 | // 圆角矩形显示 33 | missblock.css({ 34 | display: 'block', 35 | top: `${CoordinateY}px`, 36 | 'background-position': `-${missblockFirst}px -${CoordinateY}px` 37 | }) 38 | // 绘制缺口,计数避免重复绘制 39 | if(targetblockTimes<1){ 40 | var missblockImage = new Image(); 41 | missblockImage.src = 'images/1.jpg'; 42 | cvas.fillStyle = "rgba(0,0,0,0.6)"; 43 | // 在指定位置绘制38x38大小的矩形 44 | cvas.fillRect(CoordinateX, CoordinateY, 38, 38); 45 | targetblockTimes += 1; 46 | }else{ 47 | console.log('missblock alredy in canvas') 48 | } 49 | // 获取鼠标到按钮的距离 50 | var disX = e.clientX - $(this).offset().left; 51 | // 提示文字设为透明 52 | jigsawTips.css('opacity', '0') 53 | // 监听鼠标移动事件 54 | jigsaw.bind('mousemove', function(e) { 55 | mouseMoves(e, disX) 56 | }) 57 | 58 | // 监听mouseup,根据滑块位置判断结果 59 | jigsaw.bind('mouseup', function() { 60 | // 滑块移动距离等于鼠标松开时的X坐标减去鼠标按下时的X坐标 61 | var circleMouseup = jigsawCircle.offset().left; 62 | var endPosition = circleMouseup - circleMousedown; 63 | // 误差在2px以内则算成功 64 | if (Math.abs(endPosition - CoordinateX + missblockFirst) > 2) { 65 | console.log('验证失败') 66 | // 缺块和滑块归位 67 | jigsawCircle.css('left', '0px'); 68 | missblock.css('left', '10px'); 69 | // 显示提示文字 70 | jigsawTips.css('opacity', '1'); 71 | } else { 72 | alert('您已完成拼图,通过验证'); 73 | } 74 | // 移除鼠标事件监听 75 | jigsaw.unbind('mousemove') 76 | jigsaw.unbind('mouseup') 77 | }) 78 | }) 79 | } 80 | }) 81 | 82 | function mouseMoves(e, distanceX) { 83 | // 滑块移动范围控制在滑轨中,不可超出 84 | var jigsawCirclePosition = e.clientX - distanceX - $(jigsawTrack).offset().left; 85 | var jigsawTrackWidth = jigsawTrack.width(); // 滑轨长度 86 | if (jigsawCirclePosition < 0) { 87 | jigsawCirclePosition = 0 88 | }else if (jigsawCirclePosition > jigsawTrackWidth) { 89 | jigsawCirclePosition = jigsawTrackWidth 90 | } 91 | //实时显示滑块和圆角矩形的位置 92 | jigsawCircle.css('left', `${jigsawCirclePosition}px`) 93 | missblock.css('left', `${jigsawCirclePosition + missblockFirst}px`) 94 | } -------------------------------------------------------------------------------- /09/captcha/mousemove.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo 6 | 60 | 97 | 98 | 99 |
100 |
101 |
102 | 103 |
104 |
105 | 106 |
107 |
108 | 109 |
提示:页面记录绿幕中的鼠标轨迹,并在下方显示
110 | 111 |
112 |
113 | 114 | 115 | -------------------------------------------------------------------------------- /10/10-1/custom64.py: -------------------------------------------------------------------------------- 1 | class Custom64: 2 | comparison = {'0': 'A', '1': 'B', '2': 'C', '3': 'D', '4': 'E', 3 | '5': 'F', '6': 'G', '7': 'H', '8': 'I', '9': 'J', 4 | '10': 'K', '11': 'L', '12': 'M', '13': 'N', '14': 'O', 5 | '15': 'P', '16': 'Q', '17': 'R', '18': 'S', '19': 'T', 6 | '20': 'U', '21': 'V', '22': 'W', '23': 'X', '24': 'Y', 7 | '25': 'Z', '26': 'a', '27': 'b', '28': 'c', '29': 'd', 8 | '30': 'e', '31': 'f', '32': 'g', '33': 'h', '34': 'i', 9 | '35': 'j', '36': 'k', '37': 'l', '38': 'm', '39': 'n', 10 | '40': 'o', '41': 'p', '42': 'q', '43': 'r', '44': 's', 11 | '45': 't', '46': 'u', '47': 'v', '48': 'w', '49': 'x', 12 | '50': 'y', '51': 'z', '52': '0', '53': '1', '54': '2', 13 | '55': '3', '56': '4', '57': '5', '58': '6', '59': '7', 14 | '60': '8', '61': '9', '62': '+', '63': '/', '65': '=', 15 | } 16 | 17 | def encode(self, value: str, threshold: int = 4) -> str: 18 | # 对传入的字符进行编码,并返回编码结果 19 | value = ''.join(['0' + bin(ord(t))[2:] for t in value]) 20 | inputs = self.shift(value, threshold) 21 | result = '' 22 | for i in inputs: 23 | if i == '0' * threshold: 24 | # 全为0则视为补位 25 | encoding = 65 26 | else: 27 | encoding = 0 28 | for key, v in enumerate(i): 29 | # 二进制数按权相加得到十进制数 30 | val = int(v) * pow(2, len(i) - 1 - key) 31 | encoding += val 32 | # 从对照表中取值 33 | after = self.comparison.get(str(encoding)) 34 | result += after 35 | return result 36 | 37 | def decode(self, value: str, threshold: int, group: int = 8) -> str: 38 | """对传入的字符串解码,得到原字符""" 39 | result = [] 40 | coder = self.str2binary(value, threshold=threshold) 41 | bins = self.shift(''.join(coder), group) 42 | for i in range(len(bins)): 43 | binary = ''.join(bins)[i * group: (i + 1) * group] 44 | if binary != '0' * group: 45 | # 如果全为0则视为补位,无需处理 46 | result.append(''.join([chr(i) for i in [int(b, 2) for b in binary.split(' ')]])) 47 | return ''.join(result) 48 | 49 | def str2binary(self, value: str, threshold: int = 6) -> list: 50 | """字符串转十进制再转二进制""" 51 | result = [] 52 | values = self.str2decimal(value) 53 | for i in values: 54 | # 判断是否为补位 55 | if i == '65': 56 | val = '0' * threshold 57 | else: 58 | val = '{:0{threshold}b}'.format(int(i), threshold=threshold) 59 | result.append(val) 60 | return result 61 | 62 | @staticmethod 63 | def shift(value: str, threshold: int, group: int = 24) -> list: 64 | """位数转换""" 65 | remainder = len(value) % group 66 | if remainder: 67 | # 如果有余数,则说明需要用0补位 68 | padding = '0' * (group - remainder) 69 | value += padding 70 | # 按照threshold值切割字符 71 | result = [value[i:i + threshold] for i in range(0, len(value), threshold)] 72 | return result 73 | 74 | def str2decimal(self, value: str) -> list: 75 | """使用Base64编码表做对照,取出字符串对应的十进制数""" 76 | keys = [] 77 | for t in value: 78 | for k, v in self.comparison.items(): 79 | if v == t: 80 | keys.append(k) 81 | return keys 82 | 83 | 84 | if __name__ == '__main__': 85 | # threshold 的值建议为 4/5/6 86 | cus = Custom64() 87 | encode_res = cus.encode('async', threshold=5) 88 | decode_res = cus.decode(encode_res, threshold=5) 89 | print(encode_res) 90 | print(decode_res) -------------------------------------------------------------------------------- /09/captcha/clicks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 45 | 46 | 47 | 48 |
49 |

点选验证码(Canvas)

50 |

点选验证码在图片显示4-5个字,要求用户依次点击2-3个字

51 |

文字可以用其他图形代替,也可以在此基础上将文字进行变形、模糊处理

52 |
53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 |
76 |
77 | 78 |
79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /04/4-3/4-3-2/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Steamboat-反爬虫练习 9 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 84 | 85 | 86 | 87 |
88 |

“挑战者”徒步旅行活动安全公告

89 |
90 |

我们要挑战的是最长的山路,我们不会轻言放弃。

91 |

但是命是自己的!行程中要注意安全,紧跟团队。如有身体不适请立即联系医护人员。没有命,就没有挑战。以下列出本次活动规范,请大家仔细阅读并相互传播。

92 |

93 |
94 | 95 |
96 |
97 |
98 | 99 |
100 |
101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /09/captcha/nomal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 45 | 46 | 47 | 48 |
49 |

字符验证码

50 |

字符验证码主要以数字和英文字母为主,辅以部分干扰线和彩色噪点

51 |

并且对字符元素使用随机颜色,甚至是角度倾斜

52 |
53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 | 验证码 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 |
84 | 85 | 86 |
87 | 88 |
89 |
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /09/captcha/words.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 45 | 46 | 47 | 48 |
49 |

字符验证码

50 |

字符验证码主要以数字和英文字母为主,辅以部分干扰线和彩色噪点

51 |

并且对字符元素使用随机颜色,甚至是角度倾斜

52 |
53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 | 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 |
84 | 85 | 86 |
87 | 88 |
89 |
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /09/captcha/mathes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 45 | 46 | 47 | 48 |
49 |

计算型验证码

50 |

计算型验证码主要通过主观的数学计算区分人类和机器

51 |

通常只有加、减、乘,而没有除,因为除法的结果不适合用来验证。

52 |
53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 | 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 |
84 | 85 | 86 |
87 | 88 |
89 |
90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /09/captcha/sliders.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 46 | 47 | 48 | 49 |
50 |

滑动验证码

51 |

滑动验证码属于行为验证码,需要通过人为滑动指定的滑块才能通过验证

52 |

滑块会有起点与终点,相比“眼睛”来说,手动的耗时更长

53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 |
61 | 62 |
63 |
64 |
65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 |
>>
76 |
验证通过 !
77 |
78 |
79 |
80 |
81 | 82 |
83 | 84 |
85 |
86 | 87 | 88 |
89 | 90 |
91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /09/captcha/jigsawCanvas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 46 | 47 | 48 | 49 |
50 |

滑动拼图验证码(Canvas)

51 |

Canvas 将背景和缺口合并

52 |

要将指定的缺块滑到缺口处,才能通过验证

53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 |
61 | 62 |
63 |
64 |
65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 |
76 | 77 |
78 |
79 |
80 | 81 | 请滑动圆点以完成拼图 82 |
83 |
84 |
85 |
86 |
87 | 88 |
89 | 90 | 91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /09/captcha/js/jigsawCanvas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 46 | 47 | 48 | 49 |
50 |

滑动拼图验证码(Canvas)

51 |

Canvas 将背景和缺口合并

52 |

要将指定的缺块滑到缺口处,才能通过验证

53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 |
61 | 62 |
63 |
64 |
65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 |
76 | 77 |
78 |
79 |
80 | 81 | 请滑动圆点以完成拼图 82 |
83 |
84 |
85 |
86 |
87 | 88 |
89 | 90 | 91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /09/captcha/js/clicks.js: -------------------------------------------------------------------------------- 1 | /* 点选验证码 */ 2 | 3 | getChinese=function(){ 4 | // 随机汉字 5 | eval( "var singleStr=" + '"\\u' + (Math.round(Math.random() * 20901) + 19968).toString(16)+'"'); 6 | return singleStr; 7 | } 8 | 9 | $(function(){ 10 | var clickCanvas = document.getElementById('clickCanvas'); 11 | var cvas = clickCanvas.getContext('2d') 12 | var divTips = document.getElementById('divTips'); 13 | var images = new Image(); 14 | var fontSizes = 26; // 字体大小 15 | images.src = 'images/3.jpg'; 16 | 17 | images.onload = function doCanvas(){ 18 | cvas.drawImage(images, 0, 0, clickCanvas.width, clickCanvas.height); 19 | cvas.save(); 20 | cvas.font = `${fontSizes}px Arial`; 21 | cvas.fillStyle = '#ffffff'; 22 | var positions = [] 23 | var chineseStr = []; 24 | var shifted = []; 25 | var targets = []; 26 | var randTimes = 0; 27 | var userClick = []; 28 | var clickTimes = 0; 29 | 30 | function getPosition(){ 31 | // X 需要按文字顺序安排 32 | var positionX_1 = randNumber(20, 50); 33 | var positionX_2 = randNumber(70, 170); 34 | var positionX_3 = randNumber(190, 250); 35 | var positionX_4 = randNumber(270, 370); 36 | positions = [positionX_1, positionX_2, positionX_3, positionX_4] 37 | } getPosition(); 38 | 39 | function chineseArray(){ 40 | for(var i=0;i<4;i++){ 41 | // 获取汉字并生成一定规律的随机座标 42 | var positionCommonY = randNumber(50, 220); // Y 随机 43 | var positionX = positions[i]; 44 | var chinese = getChinese(); 45 | var chineseStrPosition = {chinese, positionX, positionCommonY} 46 | chineseStr.push(chineseStrPosition) 47 | } 48 | console.log(chineseStr) 49 | }chineseArray(); 50 | 51 | function canvasChinese(){ 52 | // 绘制文字 53 | for(var i=0;i<4;i++){ 54 | data = chineseStr[i] 55 | cvas.fillText(data.chinese, data.positionX, data.positionCommonY) 56 | } 57 | }canvasChinese(); 58 | 59 | function chinessCopyShow(){ 60 | // 汉字坐标数组拷贝 61 | var chineseStrCopy = [] 62 | for(var i=0;i userClick[0].x && 107 | data0.positionCommonY + fontSizes > userClick[0].y && 108 | data1.positionX + fontSizes > userClick[1].x && 109 | data1.positionCommonY + fontSizes > userClick[1].y){ 110 | divTips.innerHTML = '通过验证'; 111 | console.log('ok') 112 | }else{ 113 | 114 | divTips.innerHTML = '验证失败'; 115 | console.log('no!') 116 | } 117 | 118 | } 119 | 120 | } 121 | } 122 | 123 | 124 | 125 | 126 | }) -------------------------------------------------------------------------------- /09/captcha/jigsaw.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | Steamboat-反爬虫练习 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 46 | 47 | 48 | 49 |
50 |

滑动拼图验证码

51 |

滑动拼图验证码中,目标位置是随机的

52 |

要将指定的缺块滑到缺口处,才能通过验证

53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 |
61 | 62 |
63 |
64 |
65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 |
74 |
75 |
76 | 77 |
78 |
79 |
80 |
81 | 82 | 请滑动圆点以完成拼图 83 |
84 |
85 |
86 |
87 |
88 | 89 |
90 | 91 | 92 |
93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /07/7-4/template/details.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Steamboat-反爬虫练习 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 28 | 72 | 73 | 74 | 75 |
76 |

华为 P30 发布会在上海举行

77 |

华为P30系列新机国行版发布会,同时EMUI9.1操作系统或许也将同步面向国内消费者。

78 |
79 |
80 |
81 |
82 | HUAWEI P30 83 |
84 |

HUAWEI P30

85 |

New|No price

86 |

关注度:33870|商品详情

87 |
88 |
89 |
90 |
91 |
92 | HUAWEI P30Pro 93 |
94 |

HUAWEI P30Pro

95 |

New|No price

96 |

关注度:35870|商品详情

97 |
98 |
99 |
100 |
101 |
102 | HUAWEI P30 103 |
104 |

HUAWEI P30

105 |

New|No price

106 |

关注度:33870|商品详情

107 |
108 |
109 |
110 |
111 |
112 | Magic2 113 |
114 |

Magic2

115 |

New|¥3499

116 |

关注度:53870|商品详情

117 |
118 |
119 |
120 | 121 |
122 |
123 | Mate20 124 |
125 |

Mate20

126 |

New|¥3499

127 |

关注度:103870|商品详情

128 |
129 |
130 |
131 |
132 |
133 | Mate20X 134 |
135 |

Mate20X

136 |

New|¥4499

137 |

关注度:63870|商品详情

138 |
139 |
140 |
141 |
142 |
143 | Mate20Pro 144 |
145 |

Mate20Pro

146 |

New|¥5499

147 |

关注度:30036|商品详情

148 |
149 |
150 |
151 |
152 |
153 | Mate20Pro 154 |
155 |

Mate20Pro

156 |

New|¥5499

157 |

关注度:30036|商品详情

158 |
159 |
160 |
161 |
162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /04/4-3/4-3-2/static/md5.js: -------------------------------------------------------------------------------- 1 | /* 2 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 3 | * Digest Algorithm, as defined in RFC 1321. 4 | * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet 6 | * Distributed under the BSD License 7 | * See http://pajhome.org.uk/crypt/md5 for more info. 8 | */ 9 | 10 | /* 11 | * Configurable variables. You may need to tweak these to be compatible with 12 | * the server-side, but the defaults work in most cases. 13 | */ 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ 16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ 17 | 18 | /* 19 | * These are the functions you'll usually want to call 20 | * They take string arguments and return either hex or base-64 encoded strings 21 | */ 22 | function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} 23 | function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} 24 | function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} 25 | function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } 26 | function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } 27 | function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } 28 | 29 | /* 30 | * Perform a simple self-test to see if the VM is working 31 | */ 32 | function md5_vm_test() 33 | { 34 | return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; 35 | } 36 | 37 | /* 38 | * Calculate the MD5 of an array of little-endian words, and a bit length 39 | */ 40 | function core_md5(x, len) 41 | { 42 | /* append padding */ 43 | x[len >> 5] |= 0x80 << ((len) % 32); 44 | x[(((len + 64) >>> 9) << 4) + 14] = len; 45 | 46 | var a = 1732584193; 47 | var b = -271733879; 48 | var c = -1732584194; 49 | var d = 271733878; 50 | 51 | for(var i = 0; i < x.length; i += 16) 52 | { 53 | var olda = a; 54 | var oldb = b; 55 | var oldc = c; 56 | var oldd = d; 57 | 58 | a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); 59 | d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); 60 | c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); 61 | b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); 62 | a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); 63 | d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); 64 | c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); 65 | b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); 66 | a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); 67 | d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); 68 | c = md5_ff(c, d, a, b, x[i+10], 17, -42063); 69 | b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); 70 | a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); 71 | d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); 72 | c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); 73 | b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); 74 | 75 | a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); 76 | d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); 77 | c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); 78 | b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); 79 | a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); 80 | d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); 81 | c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); 82 | b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); 83 | a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); 84 | d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); 85 | c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); 86 | b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); 87 | a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); 88 | d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); 89 | c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); 90 | b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); 91 | 92 | a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); 93 | d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); 94 | c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); 95 | b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); 96 | a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); 97 | d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); 98 | c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); 99 | b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); 100 | a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); 101 | d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); 102 | c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); 103 | b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); 104 | a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); 105 | d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); 106 | c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); 107 | b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); 108 | 109 | a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); 110 | d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); 111 | c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); 112 | b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); 113 | a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); 114 | d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); 115 | c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); 116 | b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); 117 | a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); 118 | d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); 119 | c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); 120 | b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); 121 | a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); 122 | d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); 123 | c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); 124 | b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); 125 | 126 | a = safe_add(a, olda); 127 | b = safe_add(b, oldb); 128 | c = safe_add(c, oldc); 129 | d = safe_add(d, oldd); 130 | } 131 | return Array(a, b, c, d); 132 | 133 | } 134 | 135 | /* 136 | * These functions implement the four basic operations the algorithm uses. 137 | */ 138 | function md5_cmn(q, a, b, x, s, t) 139 | { 140 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); 141 | } 142 | function md5_ff(a, b, c, d, x, s, t) 143 | { 144 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); 145 | } 146 | function md5_gg(a, b, c, d, x, s, t) 147 | { 148 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); 149 | } 150 | function md5_hh(a, b, c, d, x, s, t) 151 | { 152 | return md5_cmn(b ^ c ^ d, a, b, x, s, t); 153 | } 154 | function md5_ii(a, b, c, d, x, s, t) 155 | { 156 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); 157 | } 158 | 159 | /* 160 | * Calculate the HMAC-MD5, of a key and some data 161 | */ 162 | function core_hmac_md5(key, data) 163 | { 164 | var bkey = str2binl(key); 165 | if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); 166 | 167 | var ipad = Array(16), opad = Array(16); 168 | for(var i = 0; i < 16; i++) 169 | { 170 | ipad[i] = bkey[i] ^ 0x36363636; 171 | opad[i] = bkey[i] ^ 0x5C5C5C5C; 172 | } 173 | 174 | var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); 175 | return core_md5(opad.concat(hash), 512 + 128); 176 | } 177 | 178 | /* 179 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally 180 | * to work around bugs in some JS interpreters. 181 | */ 182 | function safe_add(x, y) 183 | { 184 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); 185 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); 186 | return (msw << 16) | (lsw & 0xFFFF); 187 | } 188 | 189 | /* 190 | * Bitwise rotate a 32-bit number to the left. 191 | */ 192 | function bit_rol(num, cnt) 193 | { 194 | return (num << cnt) | (num >>> (32 - cnt)); 195 | } 196 | 197 | /* 198 | * Convert a string to an array of little-endian words 199 | * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. 200 | */ 201 | function str2binl(str) 202 | { 203 | var bin = Array(); 204 | var mask = (1 << chrsz) - 1; 205 | for(var i = 0; i < str.length * chrsz; i += chrsz) 206 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); 207 | return bin; 208 | } 209 | 210 | /* 211 | * Convert an array of little-endian words to a string 212 | */ 213 | function binl2str(bin) 214 | { 215 | var str = ""; 216 | var mask = (1 << chrsz) - 1; 217 | for(var i = 0; i < bin.length * 32; i += chrsz) 218 | str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); 219 | return str; 220 | } 221 | 222 | /* 223 | * Convert an array of little-endian words to a hex string. 224 | */ 225 | function binl2hex(binarray) 226 | { 227 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; 228 | var str = ""; 229 | for(var i = 0; i < binarray.length * 4; i++) 230 | { 231 | str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + 232 | hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); 233 | } 234 | return str; 235 | } 236 | 237 | /* 238 | * Convert an array of little-endian words to a base-64 string 239 | */ 240 | function binl2b64(binarray) 241 | { 242 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 243 | var str = ""; 244 | for(var i = 0; i < binarray.length * 4; i += 3) 245 | { 246 | var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) 247 | | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) 248 | | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); 249 | for(var j = 0; j < 4; j++) 250 | { 251 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; 252 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); 253 | } 254 | } 255 | return str; 256 | } 257 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 246 | 247 | 248 | 250 | 251 | 306 | 307 | 308 | 316 | 317 | 318 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 |