cookie_pool.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on 2018/12/27 11:32 AM
  4. ---------
  5. @summary: cookie池
  6. ---------
  7. @author: Boris
  8. @email: boris_liu@foxmail.com
  9. """
  10. import abc
  11. import datetime
  12. import random
  13. import time
  14. import warnings
  15. from collections import Iterable
  16. from enum import Enum, unique
  17. import requests
  18. from feapder.db.mongodb import MongoDB
  19. import feapder.utils.tools as tools
  20. from feapder import setting
  21. from feapder.network import user_agent
  22. from feapder.db.mysqldb import MysqlDB
  23. from feapder.db.redisdb import RedisDB
  24. from feapder.utils import metrics
  25. from feapder.utils.log import log
  26. from feapder.utils.redis_lock import RedisLock
  27. from feapder.utils.tools import send_msg
  28. from feapder.utils.webdriver import WebDriver
  29. class CookiePoolInterface(metaclass=abc.ABCMeta):
  30. """
  31. cookie pool interface
  32. """
  33. @abc.abstractmethod
  34. def create_cookie(self, *args, **kwargs):
  35. raise NotImplementedError
  36. @abc.abstractmethod
  37. def get_cookie(self, *args, **kwargs):
  38. raise NotImplementedError
  39. @abc.abstractmethod
  40. def del_cookie(self, *args, **kwargs):
  41. raise NotImplementedError
  42. @abc.abstractmethod
  43. def run(self):
  44. raise NotImplementedError
  45. class PageCookiePool(CookiePoolInterface):
  46. """
  47. 由页面产生的cookie 不需要用户登陆
  48. """
  49. def __init__(
  50. self,
  51. redis_key,
  52. page_url=None,
  53. min_cookies=10000,
  54. must_contained_keys=(),
  55. keep_alive=False,
  56. **kwargs,
  57. ):
  58. """
  59. @param redis_key: 项目名
  60. @param page_url: 生产cookie的url
  61. @param min_cookies: 最小cookie数
  62. @param must_contained_keys: cookie 必须包含的key
  63. @param keep_alive: 当cookie数量足够是是否保持随时待命,生产cookie的状态。False为否,满足则退出
  64. ---
  65. @param kwargs: WebDriver的一些参数
  66. load_images: 是否加载图片
  67. user_agent_pool: user-agent池 为None时不使用
  68. proxies_pool: ;代理池 为None时不使用
  69. headless: 是否启用无头模式
  70. driver_type: web driver 类型
  71. timeout: 请求超时时间 默认16s
  72. window_size: 屏幕分辨率 (width, height)
  73. """
  74. self._redisdb = RedisDB()
  75. self._tab_cookie_pool = "{}:l_cookie_pool".format(redis_key)
  76. self._tab_cookie_pool_last_count = "{}:str_cookie_pool_count".format(
  77. redis_key
  78. ) # 存储上一次统计cookie 数量的时间,格式为 时间戳:数量
  79. self._page_url = page_url
  80. self._min_cookies = min_cookies
  81. self._must_contained_keys = must_contained_keys
  82. self._keep_alive = keep_alive
  83. self._kwargs = kwargs
  84. self._kwargs.setdefault("load_images", False)
  85. self._kwargs.setdefault("headless", True)
  86. def create_cookie(self):
  87. """
  88. 可能会重写
  89. @return:
  90. """
  91. url = self._page_url
  92. header = {
  93. "Upgrade-Insecure-Requests": "1",
  94. "User-Agent": user_agent.get()
  95. }
  96. res = requests.get(url, headers=header)
  97. cookies = requests.utils.dict_from_cookiejar(res.cookies)
  98. return cookies
  99. def add_cookies(self, cookies):
  100. log.info("添加cookie {}".format(cookies))
  101. self._redisdb.lpush(self._tab_cookie_pool, cookies)
  102. def run(self):
  103. while True:
  104. try:
  105. now_cookie_count = self._redisdb.lget_count(self._tab_cookie_pool)
  106. need_cookie_count = self._min_cookies - now_cookie_count
  107. if need_cookie_count > 0:
  108. log.info(
  109. "当前cookie数为 {} 小于 {}, 生产cookie".format(
  110. now_cookie_count, self._min_cookies
  111. )
  112. )
  113. try:
  114. print('????')
  115. cookies = self.create_cookie()
  116. if cookies:
  117. self.add_cookies(cookies)
  118. except Exception as e:
  119. log.exception(e)
  120. else:
  121. log.info("当前cookie数为 {} 数量足够 暂不生产".format(now_cookie_count))
  122. # 判断cookie池近一分钟数量是否有变化,无变化则认为爬虫不再用了,退出
  123. last_count_info = self._redisdb.strget(
  124. self._tab_cookie_pool_last_count
  125. )
  126. if not last_count_info:
  127. self._redisdb.strset(
  128. self._tab_cookie_pool_last_count,
  129. "{}:{}".format(time.time(), now_cookie_count),
  130. )
  131. else:
  132. last_time, last_count = last_count_info.split(":")
  133. last_time = float(last_time)
  134. last_count = int(last_count)
  135. if time.time() - last_time > 60:
  136. if now_cookie_count == last_count:
  137. log.info("近一分钟,cookie池数量无变化,判定爬虫未使用,退出生产")
  138. break
  139. else:
  140. self._redisdb.strset(
  141. self._tab_cookie_pool_last_count,
  142. "{}:{}".format(time.time(), now_cookie_count),
  143. )
  144. if self._keep_alive:
  145. log.info("sleep 10")
  146. tools.delay_time(10)
  147. else:
  148. break
  149. except Exception as e:
  150. log.exception(e)
  151. tools.delay_time(1)
  152. def get_cookie(self, wait_when_null=True):
  153. while True:
  154. try:
  155. cookie_info = self._redisdb.rpoplpush(self._tab_cookie_pool)
  156. if not cookie_info and wait_when_null:
  157. log.info("暂无cookie 生产中...")
  158. self._keep_alive = False
  159. self._min_cookies = 1
  160. with RedisLock(
  161. key=self._tab_cookie_pool, lock_timeout=3600, wait_timeout=5
  162. ) as _lock:
  163. if _lock.locked:
  164. self.run()
  165. continue
  166. return eval(cookie_info) if cookie_info else {}
  167. except Exception as e:
  168. log.exception(e)
  169. tools.delay_time(1)
  170. def del_cookie(self, cookies):
  171. self._redisdb.lrem(self._tab_cookie_pool, cookies)
  172. # PageCookiePool('cookie_1',page_url="https://www.whzbtb.com/V2PRTS/PrequalificationPublicityInfoListInit.do").create_cookie()
  173. class User:
  174. def __init__(self, username, cookie):
  175. self.username = username
  176. self.cookie = cookie
  177. class LoginCookiePool(CookiePoolInterface):
  178. """
  179. 需要登陆的cookie池, 用户账号密码等信息用mysql保存
  180. """
  181. def __init__(
  182. self,
  183. redis_key,
  184. *,
  185. table_userbase,
  186. login_state_key="login_state",
  187. lock_state_key="lock_state",
  188. username_key="username",
  189. password_key="password",
  190. login_retry_times=10,
  191. ):
  192. """
  193. @param redis_key: 项目名
  194. @param table_userbase: 用户表名
  195. @param login_state_key: 登录状态列名
  196. @param lock_state_key: 封锁状态列名
  197. @param username_key: 登陆名列名
  198. @param password_key: 密码列名
  199. @param login_retry_times: 登陆失败重试次数
  200. """
  201. self._tab_cookie_pool = "{}:l_cookie_pool".format(redis_key)
  202. self._login_retry_times = login_retry_times
  203. self._table_userbase = table_userbase
  204. self._login_state_key = login_state_key
  205. self._lock_state_key = lock_state_key
  206. self._username_key = username_key
  207. self._password_key = password_key
  208. self._redisdb = RedisDB()
  209. self._mongo = MongoDB(db='user_login')
  210. def create_cookie(self, username, password):
  211. """
  212. 创建cookie
  213. @param username: 用户名
  214. @param password: 密码
  215. @return: return cookie / None
  216. """
  217. raise NotImplementedError
  218. def get_user_info(self):
  219. """
  220. 返回用户信息
  221. @return: yield username, password
  222. """
  223. return self._mongo.find(self._table_userbase,{self._lock_state_key:0,self._login_state_key:0})
  224. def handle_login_failed_user(self, username, password):
  225. """
  226. 处理登录失败的user
  227. @param username:
  228. @param password:
  229. @return:
  230. """
  231. pass
  232. def handel_exception(self, e):
  233. """
  234. 处理异常
  235. @param e:
  236. @return:
  237. """
  238. log.exception(e)
  239. def save_cookie(self, username, cookie):
  240. user_cookie = {"username": username, "cookie": cookie}
  241. self._redisdb.lpush(self._tab_cookie_pool, user_cookie)
  242. self._mongo.add(
  243. coll_name=self._table_userbase,
  244. data={self._login_state_key:1},
  245. update_columns=self._username_key,
  246. update_columns_value=username)
  247. def get_cookie(self, wait_when_null=True) -> User:
  248. while True:
  249. try:
  250. user_cookie = self._redisdb.rpoplpush(self._tab_cookie_pool)
  251. if not user_cookie and wait_when_null:
  252. log.info("暂无cookie 生产中...")
  253. self.login()
  254. continue
  255. if user_cookie:
  256. user_cookie = eval(user_cookie)
  257. return User(**user_cookie)
  258. return None
  259. except Exception as e:
  260. log.exception(e)
  261. tools.delay_time(1)
  262. def del_cookie(self, user: User):
  263. """
  264. 删除失效的cookie
  265. @param user:
  266. @return:
  267. """
  268. user_info = {"username": user.username, "cookie": user.cookie}
  269. self._redisdb.lrem(self._tab_cookie_pool, user_info)
  270. self._mongo.add(
  271. coll_name=self._table_userbase,
  272. data={self._login_state_key: 1},
  273. update_columns=self._username_key,
  274. update_columns_value=user.username)
  275. def user_is_locked(self, user: User):
  276. self._mongo.add(
  277. coll_name=self._table_userbase,
  278. data={self._lock_state_key: 1},
  279. update_columns=self._username_key,
  280. update_columns_value=user.username)
  281. def run(self):
  282. with RedisLock(
  283. key=self._tab_cookie_pool, lock_timeout=3600, wait_timeout=100
  284. ) as _lock:
  285. if _lock.locked:
  286. user_infos = self.get_user_info()
  287. if not isinstance(user_infos, Iterable):
  288. raise ValueError("get_user_info 返回值必须可迭代")
  289. if not user_infos:
  290. log.info("无可用用户")
  291. for info in user_infos:
  292. username = info.get("username")
  293. password = info.get("password")
  294. for i in range(self._login_retry_times):
  295. try:
  296. cookie = self.create_cookie(username, password)
  297. if cookie:
  298. self.save_cookie(username, cookie)
  299. else:
  300. self.handle_login_failed_user(username, password)
  301. break
  302. except Exception as e:
  303. self.handel_exception(e)
  304. else:
  305. self.handle_login_failed_user(username, password)
  306. login = run
  307. @unique
  308. class LimitTimesUserStatus(Enum):
  309. # 使用状态
  310. USED = "used"
  311. SUCCESS = "success"
  312. OVERDUE = "overdue" # cookie 过期
  313. SLEEP = "sleep"
  314. EXCEPTION = "exception"
  315. # 登陆状态
  316. LOGIN_SUCCESS = "login_success"
  317. LOGIN_FALIED = "login_failed"
  318. class LimitTimesUser:
  319. """
  320. 有次数限制的账户
  321. 基于本地做的缓存,不支持多进程调用
  322. """
  323. ACCOUNT_INFO_KEY = "accounts:h_account_info" # 存储cookie的redis key
  324. SITE_NAME = "" # 网站名
  325. redisdb = None
  326. def __init__(
  327. self,
  328. username,
  329. password,
  330. max_search_times,
  331. proxies=None,
  332. search_interval=0,
  333. **kwargs,
  334. ):
  335. """
  336. @param username:
  337. @param password:
  338. @param max_search_times:
  339. @param proxies:
  340. @param search_interval: 调用时间间隔。 支持元组 指定间隔的时间范围 如(5,10)即5到10秒;或直接传整数
  341. """
  342. self.__dict__.update(kwargs)
  343. self.username = username
  344. self.password = password
  345. self.max_search_times = max_search_times
  346. self.proxies = proxies
  347. self.search_interval = search_interval
  348. self.delay_use = 0 # 延时使用,用于等待解封的用户
  349. if isinstance(search_interval, (tuple, list)):
  350. if len(search_interval) != 2:
  351. raise ValueError("search_interval 需传递两个值的元组或列表。如(5,10)即5到10秒")
  352. self.used_for_time_length = (
  353. search_interval[1] * 5
  354. ) # 抢占式爬虫独享cookie时间,这段时间内其他爬虫不可抢占
  355. else:
  356. self.used_for_time_length = (
  357. search_interval * 5
  358. ) # 抢占式爬虫独享cookie时间,这段时间内其他爬虫不可抢占
  359. self.account_info = {
  360. "login_time": 0,
  361. "cookies": {},
  362. "search_times": 0,
  363. "last_search_time": 0,
  364. "used_for_spider_name": None, # 只被某个爬虫使用 其他爬虫不可使用
  365. "init_search_times_time": 0, # 初始化搜索次数的时间
  366. }
  367. if not self.__class__.redisdb:
  368. self.__class__.redisdb = RedisDB()
  369. self.sync_account_info_from_redis()
  370. self.__init_metrics()
  371. def __init_metrics(self):
  372. """
  373. 初始化打点系统
  374. @return:
  375. """
  376. metrics.init(**setting.METRICS_OTHER_ARGS)
  377. def record_user_status(self, status: LimitTimesUserStatus):
  378. metrics.emit_counter(f"{self.username}:{status.value}", 1, classify="users")
  379. def __repr__(self):
  380. return "<LimitTimesUser {} | cookies:{}>".format(self.username, self.cookies)
  381. def __eq__(self, other):
  382. return self.username == other.username
  383. def sync_account_info_from_redis(self):
  384. account_info = self.redisdb.hget(self.ACCOUNT_INFO_KEY, self.username)
  385. if account_info:
  386. account_info = eval(account_info)
  387. self.account_info.update(account_info)
  388. @property
  389. def cookies(self):
  390. cookies = self.account_info.get("cookies")
  391. return cookies
  392. def set_cookies(self, cookies):
  393. self.account_info["cookies"] = cookies
  394. return self.redisdb.hset(
  395. self.ACCOUNT_INFO_KEY, self.username, self.account_info
  396. )
  397. def set_login_time(self, login_time=None):
  398. self.account_info["login_time"] = login_time or time.time()
  399. return self.redisdb.hset(
  400. self.ACCOUNT_INFO_KEY, self.username, self.account_info
  401. )
  402. def get_login_time(self):
  403. return self.account_info.get("login_time")
  404. def is_time_to_login(self):
  405. return time.time() - self.get_login_time() > 40 * 60
  406. def get_last_search_time(self):
  407. return self.account_info.get("last_search_time", 0)
  408. def is_time_to_search(self):
  409. if self.delay_use:
  410. is_time = time.time() - self.get_last_search_time() > self.delay_use
  411. if is_time:
  412. self.delay_use = 0
  413. else:
  414. is_time = time.time() - self.get_last_search_time() > (
  415. random.randint(*self.search_interval)
  416. if isinstance(self.search_interval, (tuple, list))
  417. else self.search_interval
  418. )
  419. return is_time
  420. @property
  421. def used_for_spider_name(self):
  422. return self.account_info.get("used_for_spider_name")
  423. @used_for_spider_name.setter
  424. def used_for_spider_name(self, spider_name):
  425. self.account_info["used_for_spider_name"] = spider_name
  426. def update_status(self):
  427. """
  428. 更新search的一些状态
  429. @return:
  430. """
  431. self.account_info["search_times"] += 1
  432. self.account_info["last_search_time"] = time.time()
  433. return self.redisdb.hset(
  434. self.ACCOUNT_INFO_KEY, self.username, self.account_info
  435. )
  436. @property
  437. def search_times(self):
  438. init_search_times_time = self.account_info.get("init_search_times_time")
  439. current_time = time.time()
  440. if (
  441. current_time - init_search_times_time >= 86400
  442. ): # 如果距离上次初始化搜索次数时间大于1天,则搜索次数清清零
  443. self.account_info["search_times"] = 0
  444. self.account_info["init_search_times_time"] = current_time
  445. self.redisdb.hset(self.ACCOUNT_INFO_KEY, self.username, self.account_info)
  446. return self.account_info["search_times"]
  447. def is_overwork(self):
  448. if self.search_times > self.max_search_times:
  449. log.warning("账号 {} 请求次数超限制".format(self.username))
  450. return True
  451. return False
  452. def is_at_work_time(self):
  453. if datetime.datetime.now().hour in list(range(7, 23)):
  454. return True
  455. log.warning("账号 {} 不再工作时间内".format(self.username))
  456. return False
  457. def del_cookie(self):
  458. self.account_info["cookies"] = {}
  459. return self.redisdb.hset(
  460. self.ACCOUNT_INFO_KEY, self.username, self.account_info
  461. )
  462. def create_cookie(self):
  463. """
  464. 生产cookie 有异常需要抛出
  465. @return: cookie_dict
  466. """
  467. raise NotImplementedError
  468. def login(self):
  469. """
  470. @return: 1 成功 0 失败
  471. """
  472. try:
  473. # 预检查
  474. if not self.is_time_to_login():
  475. log.info("此账号尚未到登陆时间: {}".format(self.username))
  476. time.sleep(5)
  477. return 0
  478. cookies = self.create_cookie()
  479. if not cookies:
  480. raise Exception("登陆失败 未获取到合法cookie")
  481. if not isinstance(cookies, dict):
  482. raise Exception("cookie 必须为字典格式")
  483. # 保存cookie
  484. self.set_login_time()
  485. self.set_cookies(cookies)
  486. log.info("登录成功 {}".format(self.username))
  487. self.record_user_status(LimitTimesUserStatus.LOGIN_SUCCESS)
  488. return 1
  489. except Exception as e:
  490. log.exception(e)
  491. send_msg(
  492. msg=f"{self.SITE_NAME} {self.username} 账号登陆异常 exception: {str(e)}",
  493. level="error",
  494. message_prefix=f"{self.SITE_NAME} {self.username} 账号登陆异常",
  495. )
  496. log.info("登录失败 {}".format(self.username))
  497. self.record_user_status(LimitTimesUserStatus.LOGIN_FALIED)
  498. return 0
  499. class LimitTimesUserPool:
  500. """
  501. 限制查询次数的用户的User pool
  502. 基于本地做的缓存,不支持多进程调用
  503. """
  504. LOAD_USER_INTERVAL = 60
  505. def __init__(self, *, accounts_dict, limit_user_class, support_more_client=True):
  506. """
  507. @param accounts_dic: 账户信息字典
  508. {
  509. "15011300228": {
  510. "password": "300228",
  511. "proxies": {},
  512. "max_search_times": 500,
  513. "search_interval": 1, # 使用时间间隔
  514. # 其他携带信息
  515. }
  516. }
  517. @param limit_user_class: 用户重写的 limit_user_class
  518. @param support_more_client: 是否支持多客户端 即多线程 多进程模式 (可能在计数上及使用频率上有些误差)
  519. """
  520. self.accounts_dict = accounts_dict
  521. self.limit_user_class = limit_user_class
  522. self.limit_times_users = []
  523. self.current_user_index = -1
  524. self.support_more_client = support_more_client
  525. self.last_load_user_time = 0
  526. def __load_users(self, username=None):
  527. # 装载user
  528. log.info("更新可用用户")
  529. for _username, detail in self.accounts_dict.items():
  530. if username and username != _username:
  531. continue
  532. limit_times_users = self.limit_user_class(username=_username, **detail)
  533. if limit_times_users in self.limit_times_users:
  534. continue
  535. if limit_times_users.is_overwork():
  536. continue
  537. else:
  538. if (
  539. limit_times_users.cookies or limit_times_users.login()
  540. ): # 如果有cookie 或者登陆成功 则添加到可用的user队列
  541. self.limit_times_users.append(limit_times_users)
  542. self.last_load_user_time = time.time()
  543. def get_user(
  544. self,
  545. username=None,
  546. used_for_spider_name=None,
  547. wait_when_null=True,
  548. not_limit_frequence=False,
  549. ) -> LimitTimesUser:
  550. """
  551. @params username: 获取指定的用户
  552. @params used_for_spider_name: 独享式使用,独享爬虫的名字。其他爬虫不可抢占
  553. @params wait_when_null: 无用户时是否等待
  554. @params not_limit_frequence: 不限制使用频率
  555. @return: LimitTimesUser
  556. """
  557. if not self.support_more_client:
  558. warnings.warn(
  559. "LimitTimesUserCookiePool 取查询次数等信息时基于本地做的缓存,不支持多进程或多线程",
  560. category=Warning,
  561. )
  562. self._is_show_warning = True
  563. while True:
  564. if (
  565. not self.limit_times_users
  566. or time.time() - self.last_load_user_time >= self.LOAD_USER_INTERVAL
  567. ):
  568. self.__load_users(username)
  569. if not self.limit_times_users:
  570. log.warning("无可用的用户")
  571. if wait_when_null:
  572. time.sleep(1)
  573. continue
  574. else:
  575. return None
  576. self.current_user_index += 1
  577. self.current_user_index = self.current_user_index % len(
  578. self.limit_times_users
  579. )
  580. limit_times_user = self.limit_times_users[self.current_user_index]
  581. if self.support_more_client: # 需要先同步下最新数据
  582. limit_times_user.sync_account_info_from_redis()
  583. if username and limit_times_user.username != username:
  584. log.info(
  585. "{} 为非指定用户 {}, 获取下一个用户".format(limit_times_user.username, username)
  586. )
  587. time.sleep(1)
  588. continue
  589. # 独占式使用,若为其他爬虫,检查等待使用时间是否超过独占时间,若超过则可以使用
  590. if (
  591. limit_times_user.used_for_spider_name
  592. and limit_times_user.used_for_spider_name != used_for_spider_name
  593. ):
  594. wait_time = time.time() - limit_times_user.get_last_search_time()
  595. if wait_time < limit_times_user.used_for_time_length:
  596. log.info(
  597. "用户{} 被 {} 爬虫独占,需等待 {} 秒后才可使用".format(
  598. limit_times_user.username,
  599. limit_times_user.used_for_spider_name,
  600. limit_times_user.used_for_time_length - wait_time,
  601. )
  602. )
  603. time.sleep(1)
  604. continue
  605. if (
  606. not limit_times_user.is_overwork()
  607. and limit_times_user.is_at_work_time()
  608. ):
  609. if not limit_times_user.cookies:
  610. self.limit_times_users.remove(limit_times_user)
  611. continue
  612. if not_limit_frequence or limit_times_user.is_time_to_search():
  613. limit_times_user.used_for_spider_name = used_for_spider_name
  614. limit_times_user.update_status()
  615. log.info("使用用户 {}".format(limit_times_user.username))
  616. limit_times_user.record_user_status(LimitTimesUserStatus.USED)
  617. return limit_times_user
  618. else:
  619. log.info("{} 用户使用间隔过短 查看下一个用户".format(limit_times_user.username))
  620. time.sleep(1)
  621. continue
  622. else:
  623. self.limit_times_users.remove(limit_times_user)
  624. self.current_user_index -= 1
  625. if not limit_times_user.is_at_work_time():
  626. log.warning("用户 {} 不在工作时间".format(limit_times_user.username))
  627. if wait_when_null:
  628. time.sleep(30)
  629. continue
  630. else:
  631. return None
  632. def del_user(self, username):
  633. for limit_times_user in self.limit_times_users:
  634. if limit_times_user.username == username:
  635. limit_times_user.del_cookie()
  636. self.limit_times_users.remove(limit_times_user)
  637. limit_times_user.record_user_status(LimitTimesUserStatus.OVERDUE)
  638. self.__load_users(username)
  639. break
  640. def update_cookies(self, username, cookies):
  641. for limit_times_user in self.limit_times_users:
  642. if limit_times_user.username == username:
  643. limit_times_user.set_cookies(cookies)
  644. break
  645. def delay_use(self, username, delay_seconds):
  646. for limit_times_user in self.limit_times_users:
  647. if limit_times_user.username == username:
  648. limit_times_user.delay_use = delay_seconds
  649. limit_times_user.record_user_status(LimitTimesUserStatus.SLEEP)
  650. break
  651. def record_success_user(self, username):
  652. for limit_times_user in self.limit_times_users:
  653. if limit_times_user.username == username:
  654. limit_times_user.record_user_status(LimitTimesUserStatus.SUCCESS)
  655. def record_exception_user(self, username):
  656. for limit_times_user in self.limit_times_users:
  657. if limit_times_user.username == username:
  658. limit_times_user.record_user_status(LimitTimesUserStatus.EXCEPTION)
  659. # if __name__ == '__main__':
  660. # cookiepool = PageCookiePool(redis_key='fwork:gszfcg',
  661. # page_url='http://www.ccgp-hubei.gov.cn/notice/cgyxgg/index_1.html',
  662. # driver_type='FIREFOX',
  663. # executable_path="D:\\geckodriver.exe")
  664. # cookiepool.create_cookie()