Browse Source

update generator

pull/4/merge
Germey 8 years ago
parent
commit
50d80bf7dc
  1. 34
      cookiespool/config.py
  2. 188
      cookiespool/db.py
  3. 48
      cookiespool/error.py
  4. 246
      cookiespool/generator.py
  5. 4
      cookiespool/importer.py
  6. 52
      cookiespool/tester.py
  7. 139
      cookiespool/verify.py
  8. 6
      en.py
  9. 0
      login/__init__.py
  10. 0
      login/weibo/__init__.py
  11. 231
      login/weibo/cookies.py
  12. BIN
      login/weibo/templates/1234.png
  13. BIN
      login/weibo/templates/1243.png
  14. BIN
      login/weibo/templates/1324.png
  15. BIN
      login/weibo/templates/1342.png
  16. BIN
      login/weibo/templates/1423.png
  17. BIN
      login/weibo/templates/1432.png
  18. BIN
      login/weibo/templates/2134.png
  19. BIN
      login/weibo/templates/2143.png
  20. BIN
      login/weibo/templates/2314.png
  21. BIN
      login/weibo/templates/2341.png
  22. BIN
      login/weibo/templates/2413.png
  23. BIN
      login/weibo/templates/2431.png
  24. BIN
      login/weibo/templates/3124.png
  25. BIN
      login/weibo/templates/3142.png
  26. BIN
      login/weibo/templates/3214.png
  27. BIN
      login/weibo/templates/3241.png
  28. BIN
      login/weibo/templates/3412.png
  29. BIN
      login/weibo/templates/3421.png
  30. BIN
      login/weibo/templates/4123.png
  31. BIN
      login/weibo/templates/4132.png
  32. BIN
      login/weibo/templates/4213.png
  33. BIN
      login/weibo/templates/4231.png
  34. BIN
      login/weibo/templates/4312.png
  35. BIN
      login/weibo/templates/4321.png

34
cookiespool/config.py

@ -1,29 +1,14 @@
# Redis数据库地址
REDIS_HOST = 'DataCrawl-Pool.redis.cache.chinacloudapi.cn'
REDIS_HOST = 'localhost'
# Redis端口
REDIS_PORT = 6379
# Redis密码,如无填None
REDIS_PASSWORD = 'kk7YBCEHvswKYORLA6FCF3rfpi8mZXlKnAqBZIXqXXE='
REDIS_PASSWORD = 'foobared'
# 配置信息,无需修改
REDIS_DOMAIN = '*'
REDIS_NAME = '*'
# 云打码相关配置到yundama.com申请注册
YUNDAMA_USERNAME = 'Germey'
YUNDAMA_PASSWORD = 'CQCcqc123'
YUNDAMA_APP_ID = '3372'
YUNDAMA_APP_KEY = '1b586a30bfda5c7fa71c881075ba49d0'
YUNDAMA_API_URL = 'http://api.yundama.com/api.php'
# 云打码最大尝试次数
YUNDAMA_MAX_RETRY = 20
# 产生器默认使用的浏览器
DEFAULT_BROWSER = 'Chrome'
# 产生器使用的浏览器
BROWSER_TYPE = 'Chrome'
# 产生器类,如扩展其他站点,请在此配置
GENERATOR_MAP = {
@ -35,6 +20,10 @@ TESTER_MAP = {
'weibo': 'WeiboValidTester'
}
TEST_URL_MAP = {
'weibo': 'https://m.weibo.cn/api/container/getIndex?uid=1804544030&type=uid&page=1&containerid=1076031804544030'
}
# 产生器和验证器循环周期
CYCLE = 120
@ -42,10 +31,9 @@ CYCLE = 120
API_HOST = '127.0.0.1'
API_PORT = 5000
# 进程开关
# 产生器,模拟登录添加Cookies
GENERATOR_PROCESS = True
# 验证器,循环检测数据库中Cookies是否可用,不可用删除
# 产生器开关,模拟登录添加Cookies
GENERATOR_PROCESS = False
# 验证器开关,循环检测数据库中Cookies是否可用,不可用删除
VALID_PROCESS = False
# API接口服务
API_PROCESS = True

188
cookiespool/db.py

@ -1,209 +1,83 @@
import random
import redis
from cookiespool.config import *
from cookiespool.error import *
class RedisClient(object):
def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD):
def __init__(self, type, website, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD):
"""
初始化Redis连接
:param host: 地址
:param port: 端口
:param password: 密码
"""
if password:
self._db = redis.Redis(host=host, port=port, password=password)
else:
self._db = redis.Redis(host=host, port=port)
self.domain = REDIS_DOMAIN
self.name = REDIS_NAME
self.db = redis.Redis(host=host, port=port, password=password, decode_responses=True)
self.type = type
self.website = website
def _key(self, key):
def key(self):
"""
得到格式化的key
:param key: 最后一个参数key
得到格式化的username
:param username: 最后一个参数username
:return:
"""
return "{domain}:{name}:{key}".format(domain=self.domain, name=self.name, key=key)
return "{type}:{website}".format(type=self.type, website=self.website)
def set(self, key, value):
def set(self, username, value):
"""
设置键值对
:param key:
:param username:
:param value:
:return:
"""
raise NotImplementedError
return self.db.hset(self.key(), username, value)
def get(self, key):
def get(self, username):
"""
根据键名获取键值
:param key:
:param username:
:return:
"""
raise NotImplementedError
return self.db.hget(self.key(), username)
def delete(self, key):
def delete(self, username):
"""
根据键名删除键值对
:param key:
:return:
"""
raise NotImplementedError
def keys(self):
"""
得到所有的键名
:return:
"""
return self._db.keys('{domain}:{name}:*'.format(domain=self.domain, name=self.name))
def flush(self):
"""
清空数据库, 慎用
:param username:
:return:
"""
self._db.flushall()
return self.db.hdel(self.key(), username)
class CookiesRedisClient(RedisClient):
def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, domain='cookies', name='default'):
def count(self):
"""
管理Cookies的对象
:param host: 地址
:param port: 端口
:param password: 密码
:param domain: , 如cookies, account等
:param name: 名称, 一般为站点名, weibo, 默认 default
获取数目
:return: 数目
"""
RedisClient.__init__(self, host, port, password)
self.domain = domain
self.name = name
def set(self, key, value):
try:
self._db.set(self._key(key), value)
except:
raise SetCookieError
def get(self, key):
try:
return self._db.get(self._key(key)).decode('utf-8')
except:
return None
def delete(self, key):
try:
print('Delete', key)
return self._db.delete(self._key(key))
except:
raise DeleteCookieError
return len(self.db.hlen(self.key()))
def random(self):
"""
随机得到一Cookies
随机得到键值
:return:
"""
try:
keys = self.keys()
return self._db.get(random.choice(keys))
except:
raise GetRandomCookieError
return random.choice(self.db.hvals(self.key()))
def all(self):
def usernames(self):
"""
获取所有账户, 以字典形式返回
获取所有账户信息
:return:
"""
try:
for key in self._db.keys('{domain}:{name}:*'.format(domain=self.domain, name=self.name)):
group = key.decode('utf-8').split(':')
if len(group) == 3:
username = group[2]
yield {
'username': username,
'cookies': self.get(username)
}
except Exception as e:
print(e.args)
raise GetAllCookieError
def count(self):
"""
获取当前Cookies数目
:return: 数目
"""
return len(self.keys())
class AccountRedisClient(RedisClient):
def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD, domain='account', name='default'):
RedisClient.__init__(self, host, port, password)
self.domain = domain
self.name = name
def set(self, key, value):
try:
return self._db.set(self._key(key), value)
except:
raise SetAccountError
def get(self, key):
try:
return self._db.get(self._key(key)).decode('utf-8')
except:
raise GetAccountError
return self.db.hkeys(self.key())
def all(self):
"""
获取所有账户, 以字典形式返回
获取所有键值对
:return:
"""
try:
for key in self._db.keys('{domain}:{name}:*'.format(domain=self.domain, name=self.name)):
group = key.decode('utf-8').split(':')
if len(group) == 3:
username = group[2]
yield {
'username': username,
'password': self.get(username)
}
except Exception as e:
print(e.args)
raise GetAllAccountError
def delete(self, key):
"""
通过用户名删除用户
:param key:
:return:
"""
try:
return self._db.delete(self._key(key))
except:
raise DeleteAccountError
return self.db.hgetall(self.key())
if __name__ == '__main__':
"""
conn = CookiesRedisClient()
conn.set('name', 'Mike')
conn.set('name2', 'Bob')
conn.set('name3', 'Amy')
print(conn.get('name'))
conn.delete('name')
print(conn.keys())
print(conn.random())
"""
# 测试
conn = AccountRedisClient(name='weibo')
conn2 = AccountRedisClient(name='mweibo')
accounts = conn.all()
for account in accounts:
conn2.set(account['username'], account['password'])
conn = RedisClient('accounts', 'weibo')
result = conn.set('hell2o', 'sss3s')
print(result)

48
cookiespool/error.py

@ -1,48 +0,0 @@
class CookiePoolError(Exception):
def __str__(self):
return repr('Cookie Pool Error')
class SetCookieError(CookiePoolError):
def __str__(self):
return repr('Set Cookie Error')
class GetCookieError(CookiePoolError):
def __str__(self):
return repr('Get Cookie Error')
class DeleteCookieError(CookiePoolError):
def __str__(self):
return repr('Delete Cookie Error')
class GetRandomCookieError(CookiePoolError):
def __str__(self):
return repr('Get Random Cookie Error')
class GetAllCookieError(CookiePoolError):
def __str__(self):
return repr('Get All Cookie Error')
class SetAccountError(CookiePoolError):
def __str__(self):
return repr('Set Account Error')
class DeleteAccountError(CookiePoolError):
def __str__(self):
return repr('Delete Account Error')
class GetAccountError(CookiePoolError):
def __str__(self):
return repr('Get Account Error')
class GetAllAccountError(CookiePoolError):
def __str__(self):
return repr('Get All Account Error')

246
cookiespool/generator.py

@ -1,83 +1,96 @@
import json
import requests
import time
from selenium import webdriver
from selenium.common.exceptions import WebDriverException, TimeoutException
from selenium.webdriver import DesiredCapabilities
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from cookiespool.config import *
from cookiespool.db import CookiesRedisClient, AccountRedisClient
from cookiespool.verify import Yundama
from cookiespool.db import RedisClient
from login.weibo.cookies import WeiboCookies
class CookiesGenerator(object):
def __init__(self, name='default', browser_type=DEFAULT_BROWSER):
def __init__(self, name='default'):
"""
父类, 初始化一些对象
:param name: 名称
:param browser: 浏览器, 若不使用浏览器则可设置为 None
"""
self.name = name
self.cookies_db = CookiesRedisClient(name=self.name)
self.account_db = AccountRedisClient(name=self.name)
self.browser_type = browser_type
def _init_browser(self, browser_type):
self.cookies_db = RedisClient('cookies', self.name)
self.accounts_db = RedisClient('accounts', self.name)
def __del__(self):
self.close()
def init_browser(self):
"""
通过browser参数初始化全局浏览器供模拟登录使用
:param browser: 浏览器 PhantomJS/ Chrome
:return:
"""
if browser_type == 'PhantomJS':
if BROWSER_TYPE == 'PhantomJS':
caps = DesiredCapabilities.PHANTOMJS
caps[
"phantomjs.page.settings.userAgent"] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'
self.browser = webdriver.PhantomJS(desired_capabilities=caps)
self.browser.set_window_size(1400, 500)
elif browser_type == 'Chrome':
elif BROWSER_TYPE == 'Chrome':
self.browser = webdriver.Chrome()
def new_cookies(self, username, password):
"""
新生成Cookies子类需要重写
:param username: 用户名
:param password: 密码
:return:
"""
raise NotImplementedError
def set_cookies(self, account):
def process_cookies(self, cookies):
"""
根据账户设置新的Cookies
:param account:
处理Cookies
:param cookies:
:return:
"""
results = self.new_cookies(account.get('username'), account.get('password'))
if results:
username, cookies = results
print('Saving Cookies to Redis', username, cookies)
self.cookies_db.set(username, cookies)
dict = {}
for cookie in cookies:
dict[cookie["name"]] = cookie["value"]
return dict
def run(self):
"""
运行, 得到所有账户, 然后顺次模拟登录
:return:
"""
accounts = self.account_db.all()
cookies = self.cookies_db.all()
# Account 中对应的用户
accounts = list(accounts)
# Cookies中对应的用户
valid_users = [cookie.get('username') for cookie in cookies]
print('Getting', len(accounts), 'accounts from Redis')
if len(accounts):
self._init_browser(browser_type=self.browser_type)
for account in accounts:
if not account.get('username') in valid_users:
print('Getting Cookies of ', self.name, account.get('username'), account.get('password'))
self.set_cookies(account)
print('Generator Run Finished')
accounts_usernames = self.accounts_db.usernames()
cookies_usernames = self.cookies_db.usernames()
for username in accounts_usernames:
if not username in cookies_usernames:
password = self.accounts_db.get(username)
print('正在生成Cookies', '账号', username, '密码', password)
result = self.new_cookies(username, password)
# 成功获取
if result.get('status') == 1:
cookies = self.process_cookies(result.get('content'))
print('成功获取到Cookies', cookies)
if self.cookies_db.set(username, json.dumps(cookies)):
print('成功保存Cookies')
# 密码错误,移除账号
elif result.get('status') == 2:
print(result.get('content'))
if self.accounts_db.delete(username):
print('成功删除账号')
else:
print(result.get('content'))
def close(self):
"""
关闭
:return:
"""
try:
print('Closing Browser')
self.browser.close()
@ -87,111 +100,15 @@ class CookiesGenerator(object):
class WeiboCookiesGenerator(CookiesGenerator):
def __init__(self, name='weibo', browser_type=DEFAULT_BROWSER):
"""
初始化操作, 微博需要声明一个云打码引用
:param name: 名称微博
:param browser: 使用的浏览器
"""
CookiesGenerator.__init__(self, name, browser_type)
self.name = name
self.ydm = Yundama(YUNDAMA_USERNAME, YUNDAMA_PASSWORD, YUNDAMA_APP_ID, YUNDAMA_APP_KEY)
def _success(self, username):
wait = WebDriverWait(self.browser, 5)
success = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, 'me_portrait_w')))
if success:
print('登录成功')
self.browser.get('http://weibo.cn/')
if "我的首页" in self.browser.title:
print(self.browser.get_cookies())
cookies = {}
for cookie in self.browser.get_cookies():
cookies[cookie["name"]] = cookie["value"]
print(cookies)
print('成功获取到Cookies')
return (username, json.dumps(cookies))
def new_cookies(self, username, password):
"""
生成Cookies
:param username: 用户名
:param password: 密码
:return: 用户名和Cookies
"""
print('Generating Cookies of', username)
self.browser.delete_all_cookies()
self.browser.get('http://my.sina.com.cn/profile/unlogin')
wait = WebDriverWait(self.browser, 20)
try:
login = wait.until(EC.visibility_of_element_located((By.ID, 'hd_login')))
login.click()
user = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginformlist input[name="loginname"]')))
user.send_keys(username)
psd = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginformlist input[name="password"]')))
psd.send_keys(password)
submit = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.login_btn')))
submit.click()
try:
result = self._success(username)
if result:
return result
except TimeoutException:
print('出现验证码,开始识别验证码')
yzm = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginform_yzm .yzm')))
url = yzm.get_attribute('src')
cookies = self.browser.get_cookies()
cookies_dict = {}
for cookie in cookies:
cookies_dict[cookie.get('name')] = cookie.get('value')
response = requests.get(url, cookies=cookies_dict)
result = self.ydm.identify(stream=response.content)
if not result:
print('验证码识别失败, 跳过识别')
return
door = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginform_yzm input[name="door"]')))
door.send_keys(result)
submit.click()
result = self._success(username)
if result:
return result
except WebDriverException as e:
print(e.args)
class MWeiboCookiesGenerator(CookiesGenerator):
def __init__(self, name='weibo', browser_type=DEFAULT_BROWSER):
def __init__(self, name='weibo'):
"""
初始化操作, 微博需要声明一个云打码引用
:param name: 名称微博
:param browser: 使用的浏览器
"""
CookiesGenerator.__init__(self, name, browser_type)
CookiesGenerator.__init__(self, name)
self.name = name
self.ydm = Yundama(YUNDAMA_USERNAME, YUNDAMA_PASSWORD, YUNDAMA_APP_ID, YUNDAMA_APP_KEY)
def _success(self, username):
wait = WebDriverWait(self.browser, 5)
success = wait.until(EC.visibility_of_element_located((By.CLASS_NAME, 'me_portrait_w')))
if success:
print('登录成功')
self.browser.get('http://m.weibo.cn/')
if "微博" in self.browser.title:
print(self.browser.get_cookies())
cookies = {}
for cookie in self.browser.get_cookies():
cookies[cookie["name"]] = cookie["value"]
print(cookies)
print('成功获取到Cookies')
return (username, json.dumps(cookies))
def new_cookies(self, username, password):
"""
生成Cookies
@ -199,53 +116,10 @@ class MWeiboCookiesGenerator(CookiesGenerator):
:param password: 密码
:return: 用户名和Cookies
"""
print('Generating Cookies of', username)
self.browser.delete_all_cookies()
self.browser.get('http://my.sina.com.cn/profile/unlogin')
wait = WebDriverWait(self.browser, 20)
try:
login = wait.until(EC.visibility_of_element_located((By.ID, 'hd_login')))
login.click()
user = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginformlist input[name="loginname"]')))
user.send_keys(username)
psd = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginformlist input[name="password"]')))
psd.send_keys(password)
submit = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.login_btn')))
submit.click()
try:
result = self._success(username)
if result:
return result
except TimeoutException:
print('出现验证码,开始识别验证码')
yzm = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginform_yzm .yzm')))
url = yzm.get_attribute('src')
cookies = self.browser.get_cookies()
cookies_dict = {}
for cookie in cookies:
cookies_dict[cookie.get('name')] = cookie.get('value')
response = requests.get(url, cookies=cookies_dict)
result = self.ydm.identify(stream=response.content)
if not result:
print('验证码识别失败, 跳过识别')
return
door = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, '.loginform_yzm input[name="door"]')))
door.send_keys(result)
submit.click()
result = self._success(username)
if result:
return result
except WebDriverException as e:
pass
return WeiboCookies(username, password, self.browser).main()
if __name__ == '__main__':
generator = WeiboCookiesGenerator()
generator._init_browser('Chrome')
generator.new_cookies('15197170054', 'gmwkms222')
generator.init_browser()
generator.run()

4
cookiespool/importer.py

@ -1,8 +1,8 @@
import requests
from cookiespool.db import AccountRedisClient
from cookiespool.db import RedisClient
conn = AccountRedisClient(name='weibo')
conn = RedisClient('accounts', 'weibo')
def set(account, sep='----'):
username, password = account.split(sep)

52
cookiespool/tester.py

@ -1,22 +1,21 @@
import json
from bs4 import BeautifulSoup
import requests
from requests.exceptions import ConnectionError
from cookiespool.db import *
from cookiespool.generator import WeiboCookiesGenerator
class ValidTester(object):
def __init__(self, name='default'):
self.name = name
self.cookies_db = CookiesRedisClient(name=self.name)
self.account_db = AccountRedisClient(name=self.name)
self.cookies_db = RedisClient('cookies', self.name)
self.account_db = RedisClient('accounts', self.name)
def test(self, account, cookies):
raise NotImplementedError
def run(self):
accounts = self.cookies_db.all()
print(accounts)
for account in accounts:
username = account.get('username')
cookies = self.cookies_db.get(username)
@ -26,52 +25,18 @@ class ValidTester(object):
class WeiboValidTester(ValidTester):
def __init__(self, name='weibo'):
ValidTester.__init__(self, name)
def test(self, account, cookies):
print('Testing Account', account.get('username'))
try:
cookies = json.loads(cookies)
except TypeError:
# Cookie 格式不正确
print('Invalid Cookies Value', account.get('username'))
self.cookies_db.delete(account.get('username'))
print('Deleted User', account.get('username'))
return None
try:
response = requests.get('http://weibo.cn', cookies=cookies)
if response.status_code == 200:
html = response.text
soup = BeautifulSoup(html, 'lxml')
title = soup.title.string
if title == '我的首页':
print('Valid Cookies', account.get('username'))
else:
print('Title is', title)
# Cookie已失效
print('Invalid Cookies', account.get('username'))
self.cookies_db.delete(account.get('username'))
print('Deleted User', account.get('username'))
except ConnectionError as e:
print('Error', e.args)
print('Invalid Cookies', account.get('username'))
class MWeiboValidTester(ValidTester):
def __init__(self, name='weibo'):
ValidTester.__init__(self, name)
def test(self, account, cookies):
print('Testing Account', account.get('username'))
try:
cookies = json.loads(cookies)
except TypeError:
# Cookie 格式不正确
print('Invalid Cookies Value', account.get('username'))
self.cookies_db.delete(account.get('username'))
print('Deleted User', account.get('username'))
return None
try:
test_url = 'http://m.weibo.cn/api/container/getIndex?uid=1804544030&type=uid&page=1&containerid=1076031804544030'
test_url = TEST_URL_MAP[self.name]
response = requests.get(test_url, cookies=cookies, timeout=5, allow_redirects=False)
if response.status_code == 200:
print('Valid Cookies', account.get('username'))
@ -84,6 +49,3 @@ class MWeiboValidTester(ValidTester):
print('Error', e.args)
print('Invalid Cookies', account.get('username'))
if __name__ == '__main__':
tester = WeiboValidTester()
tester.run()

139
cookiespool/verify.py

@ -1,139 +0,0 @@
import time
import requests
from requests.exceptions import ConnectionError
from cookiespool.config import *
class Yundama():
def __init__(self, username, password, app_id, app_key, api_url=YUNDAMA_API_URL):
self.username = username
self.password = password
self.app_id = str(app_id) if not isinstance(app_id, str) else app_id
self.app_key = app_key
self.api_url = api_url
def login(self):
"""
登录云打码账户
:return:
"""
try:
data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.app_id,
'appkey': self.app_key}
response = requests.post(self.api_url, data=data)
if response.status_code == 200:
result = response.json()
print(result)
if 'ret' in result.keys() and result.get('ret') < 0:
return self.error(result.get('ret'))
else:
return result
return None
except ConnectionError:
return None
def upload(self, files, timeout, code_type):
"""
上传验证码得到识别结果
:param files:
:param timeout:
:param code_type:
:return:
"""
try:
data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.app_id,
'appkey': self.app_key, 'codetype': str(code_type), 'timeout': str(timeout)}
response = requests.post(self.api_url, data=data, files=files)
if response.status_code == 200:
return response.json()
return None
except ConnectionError:
return None
def retry(self, cid, try_count=1):
"""
临时识别不出, 传入cid重试
:param cid: 验证码ID
:param try_count: 重试次数
:return: 验证码结果
"""
if try_count >= YUNDAMA_MAX_RETRY:
return None
print('Retrying: ', cid, 'Count: ', try_count)
time.sleep(2)
try:
data = {'method': 'result', 'cid': cid}
print(data)
response = requests.post(self.api_url, data=data)
if response.status_code == 200:
result = response.json()
print(result)
if 'ret' in result.keys() and result.get('ret') < 0:
print(self.error(result.get('ret')))
if result.get('ret') == 0 and 'text' in result.keys():
return result.get('text')
else:
return self.retry(cid, try_count + 1)
return None
except ConnectionError:
return None
def identify(self, file=None, stream=None, timeout=60, code_type=5000):
"""
主函数
:param file: 文件名
:param stream: 文件流, 优先于文件名
:param timeout: 超时时间
:param code_type: 验证码类型
:return: 识别结果
"""
if stream:
files = {'file': stream}
elif file:
files = {'file': open(file, 'rb')}
else:
return None
result = self.upload(files, timeout, code_type)
if 'ret' in result.keys() and result.get('ret') < 0:
print(self.error(result.get('ret')))
if result.get('text'):
print('验证码识别成功', result.get('text'))
return result.get('text')
else:
return self.retry(result.get('cid'))
def error(self, code):
"""
报错原因
:param code: 错误码
:return: 错误原因
"""
map = {
-1001: '密码错误',
-1002: '软件ID/密钥有误',
-1003: '用户被封',
-1004: 'IP被封',
-1005: '软件被封',
-1006: '登录IP与绑定的区域不匹配',
-1007: '账号余额为零',
-2001: '验证码类型有误',
-2002: '验证码图片太大',
-2003: '验证码图片损坏',
-2004: '上传验证码图片失败',
-3001: '验证码ID不存在 ',
-3002: '验证码还在识别',
-3003: '验证码识别超时',
-3004: '验证码看不清',
-3005: '验证码报错失败',
-4001: '充值卡号不正确或已使用',
-5001: '注册用户失败'
}
return '云打码' + map.get(code)
if __name__ == '__main__':
ydm = Yundama(YUNDAMA_USERNAME, YUNDAMA_PASSWORD, YUNDAMA_APP_ID, YUNDAMA_APP_KEY)
result = ydm.identify(file='getimage.jpg')
print(result)

6
en.py

@ -0,0 +1,6 @@
from cookiespool.tester import WeiboValidTester
if __name__ == '__main__':
tester = WeiboValidTester()
tester.run()

0
login/__init__.py

0
login/weibo/__init__.py

231
login/weibo/cookies.py

@ -0,0 +1,231 @@
import os
import time
from io import BytesIO
from PIL import Image
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from os import listdir
from os.path import abspath, dirname
TEMPLATES_FOLDER = dirname(abspath(__file__)) + '/templates/'
class WeiboCookies():
def __init__(self, username, password, browser):
self.url = 'https://passport.weibo.cn/signin/login?entry=mweibo&r=https://m.weibo.cn/'
self.browser = browser
self.wait = WebDriverWait(self.browser, 20)
self.username = username
self.password = password
def open(self):
"""
打开网页输入用户名密码并点击
:return: None
"""
self.browser.delete_all_cookies()
self.browser.get(self.url)
username = self.wait.until(EC.presence_of_element_located((By.ID, 'loginName')))
password = self.wait.until(EC.presence_of_element_located((By.ID, 'loginPassword')))
submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'loginAction')))
username.send_keys(self.username)
password.send_keys(self.password)
time.sleep(1)
submit.click()
def password_error(self):
"""
判断是否密码错误
:return:
"""
try:
return WebDriverWait(self.browser, 5).until(
EC.text_to_be_present_in_element((By.ID, 'errorMsg'), '用户名或密码错误'))
except TimeoutException:
return False
def login_successfully(self):
"""
判断是否登录成功
:return:
"""
try:
return bool(
WebDriverWait(self.browser, 5).until(EC.presence_of_element_located((By.CLASS_NAME, 'drop-title'))))
except TimeoutException:
return False
def get_position(self):
"""
获取验证码位置
:return: 验证码位置元组
"""
try:
img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'patt-shadow')))
except TimeoutException:
print('未出现验证码')
self.open()
time.sleep(2)
location = img.location
size = img.size
top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
'width']
return (top, bottom, left, right)
def get_screenshot(self):
"""
获取网页截图
:return: 截图对象
"""
screenshot = self.browser.get_screenshot_as_png()
screenshot = Image.open(BytesIO(screenshot))
return screenshot
def get_image(self, name='captcha.png'):
"""
获取验证码图片
:return: 图片对象
"""
top, bottom, left, right = self.get_position()
print('验证码位置', top, bottom, left, right)
screenshot = self.get_screenshot()
captcha = screenshot.crop((left, top, right, bottom))
return captcha
def is_pixel_equal(self, image1, image2, x, y):
"""
判断两个像素是否相同
:param image1: 图片1
:param image2: 图片2
:param x: 位置x
:param y: 位置y
:return: 像素是否相同
"""
# 取两个图片的像素点
pixel1 = image1.load()[x, y]
pixel2 = image2.load()[x, y]
threshold = 20
if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs(
pixel1[2] - pixel2[2]) < threshold:
return True
else:
return False
def same_image(self, image, template):
"""
识别相似验证码
:param image: 待识别验证码
:param template: 模板
:return:
"""
# 相似度阈值
threshold = 0.99
count = 0
for x in range(image.width):
for y in range(image.height):
# 判断像素是否相同
if self.is_pixel_equal(image, template, x, y):
count += 1
result = float(count) / (image.width * image.height)
if result > threshold:
print('成功匹配')
return True
return False
def detect_image(self, image):
"""
匹配图片
:param image: 图片
:return: 拖动顺序
"""
for template_name in listdir(TEMPLATES_FOLDER):
print('正在匹配', template_name)
template = Image.open(TEMPLATES_FOLDER + template_name)
if self.same_image(image, template):
# 返回顺序
numbers = [int(number) for number in list(template_name.split('.')[0])]
print('拖动顺序', numbers)
return numbers
def move(self, numbers):
"""
根据顺序拖动
:param numbers:
:return:
"""
# 获得四个按点
circles = self.browser.find_elements_by_css_selector('.patt-wrap .patt-circ')
dx = dy = 0
for index in range(4):
circle = circles[numbers[index] - 1]
# 如果是第一次循环
if index == 0:
# 点击第一个按点
ActionChains(self.browser) \
.move_to_element_with_offset(circle, circle.size['width'] / 2, circle.size['height'] / 2) \
.click_and_hold().perform()
else:
# 小幅移动次数
times = 30
# 拖动
for i in range(times):
ActionChains(self.browser).move_by_offset(dx / times, dy / times).perform()
time.sleep(1 / times)
# 如果是最后一次循环
if index == 3:
# 松开鼠标
ActionChains(self.browser).release().perform()
else:
# 计算下一次偏移
dx = circles[numbers[index + 1] - 1].location['x'] - circle.location['x']
dy = circles[numbers[index + 1] - 1].location['y'] - circle.location['y']
def get_cookies(self):
"""
获取Cookies
:return:
"""
return self.browser.get_cookies()
def main(self):
"""
破解入口
:return:
"""
self.open()
if self.password_error():
return {
'status': 2,
'content': '用户名或密码错误'
}
# 如果不需要验证码直接登录成功
if self.login_successfully():
cookies = self.get_cookies()
return {
'status': 1,
'content': cookies
}
# 获取验证码图片
image = self.get_image('captcha.png')
numbers = self.detect_image(image)
self.move(numbers)
if self.login_successfully():
cookies = self.get_cookies()
return {
'status': 1,
'content': cookies
}
else:
return {
'status': 3,
'content': '登录失败'
}
if __name__ == '__main__':
result = WeiboCookies('14773427930', 'x6pybpakq1').main()
print(result)

BIN
login/weibo/templates/1234.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
login/weibo/templates/1243.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
login/weibo/templates/1324.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
login/weibo/templates/1342.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
login/weibo/templates/1423.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
login/weibo/templates/1432.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
login/weibo/templates/2134.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
login/weibo/templates/2143.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
login/weibo/templates/2314.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
login/weibo/templates/2341.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
login/weibo/templates/2413.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
login/weibo/templates/2431.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
login/weibo/templates/3124.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
login/weibo/templates/3142.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
login/weibo/templates/3214.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
login/weibo/templates/3241.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
login/weibo/templates/3412.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
login/weibo/templates/3421.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
login/weibo/templates/4123.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
login/weibo/templates/4132.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
login/weibo/templates/4213.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
login/weibo/templates/4231.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
login/weibo/templates/4312.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
login/weibo/templates/4321.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Loading…
Cancel
Save