Skip to content

Commit

Permalink
优化异常处理逻辑;完善文档;优化 docker-compose.yml 依赖项声明
Browse files Browse the repository at this point in the history
  • Loading branch information
luolongfei committed Dec 24, 2021
1 parent 44ad20e commit 55c917d
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 39 deletions.
69 changes: 48 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
<div align="center">

[![Netflix.png](https://s4.ax1x.com/2021/12/24/TYGHXD.png)](https://s4.ax1x.com/2021/12/24/TYGHXD.png)

<h1>Netflix</h1>
监听奈飞(Netflix)密码变更邮件,自动重置密码。
</div>

### 简介
### 缘起

共享 Netflix 账户的用户,密码可能频繁被人修改,使大家无法登录。

共享 Netflix 账户的用户,最大的烦恼莫过于密码频繁被不良人修改,本项目完美解决了这个问题。基本逻辑是监听 Netflix 密码变更邮件,自动重置密码。
仅供 Netflix 账户主使用。
本项目完美解决了这个问题,基本逻辑是监听 Netflix 密码变更邮件,自动重置密码。仅供 Netflix 账户主使用。

### 使用方法

*这里只说明如何在 docker 中使用,按照步骤走即可。*
*这里只说明如何在 Docker 中使用,按照步骤走即可。*

#### 1、安装 docker
#### 1、安装 Docker

升级源并安装软件(下面两行命令二选一,根据你自己的系统)

Debian / Ubuntu

```shell
apt-get update && apt-get install -y wget vim git
```

CentOS

```shell
yum update && yum install -y wget vim git
apt-get update && apt-get install -y wget vim git # Debian / Ubuntu
yum update && yum install -y wget vim git # CentOS
```

一句话命令安装 docker
一句话命令安装 Docker

```shell
wget -qO- get.docker.com | bash
Expand All @@ -37,7 +34,7 @@ wget -qO- get.docker.com | bash
说明:请使用 KVM 架构的 VPS,OpenVZ 架构的 VPS 不支持安装 Docker,另外 CentOS 8 不支持用此脚本来安装 Docker。 更多关于 Docker
安装的内容参考 [Docker 官方安装指南](https://docs.docker.com/engine/install/)

启动 docker
启动 Docker

```shell
systemctl start docker
Expand All @@ -50,9 +47,9 @@ sudo systemctl enable docker.service
sudo systemctl enable containerd.service
```

#### 2、安装 docker-compose
#### 2、安装 Docker-compose

一句话命令安装 docker-compose,如果想自定义版本,可以修改下面的版本号(`DOCKER_COMPOSE_VER`对应的值),否则保持默认就好。
一句话命令安装 Docker-compose,如果想自定义版本,可以修改下面的版本号(`DOCKER_COMPOSE_VER`对应的值),否则保持默认就好。

```shell
DOCKER_COMPOSE_VER=1.29.2 && sudo curl -L "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VER}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose && sudo ln -snf /usr/local/bin/docker-compose /usr/bin/docker-compose && docker-compose --version
Expand All @@ -67,15 +64,45 @@ git clone https://github.com/luolongfei/netflix.git && cd netflix
#### 4、修改 .env 配置

完成步骤 3 后,现在你应该正位于源码根目录,即 `.env.example` 文件所在目录,执行

```shell
cp .env.example .env
```
然后使用`vim`修改`.env`文件中的配置项。注意在 docker 中运行的话,`DRIVER_EXECUTABLE_FILE``REDIS_HOST`以及`REDIS_PORT`的值保持默认即可。

然后使用`vim`修改`.env`文件中的配置项。注意在 Docker 中运行的话,`DRIVER_EXECUTABLE_FILE``REDIS_HOST`以及`REDIS_PORT`的值保持默认即可。

#### 5、运行

直接执行

```shell
docker-compose up -d
docker-compose up -d --build
```
执行完成后,项目便在后台跑起来了,再执行 `docker-compose ps` 可以看到程式的运行状态。

执行完成后,项目便在后台跑起来了。

#### 6、Docker-compose 常用命令

查看程式的运行状态

```shell
docker-compose ps
```
输出程序日志
```shell
docker-compose logs
```

更多 Docker-compose 命令请参考: [Docker-compose 官方指南](https://docs.docker.com/compose/reference/) 。在官网能找到所有命令。

#### 7、问答

> 如何升级到新版本呢?
>
请在`docker-compose.yml`文件所在目录,拉取最新的代码,然后同样执行`docker-compose up -d --build`,Docker 会自动使用最新的代码进行构建,
构建完跑起来后,即是最新版本。

> 非 Netflix 账户主可以使用本项目吗?
>
不能。本项目仅供 Netflix 账户主使用,因为涉及到监听 Netflix 账户的邮件,而只有 Netflix 账户主才有 Netflix 邮箱以及其密码的权限,所以只有 Netflix
账户主有权使用。
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ services:
build:
context: .
dockerfile: Dockerfile
depends_on:
- redis
container_name: netflix
volumes:
- .:/conf
Expand Down
95 changes: 77 additions & 18 deletions netflix.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def wrapper(*args, **kwargs):


class Netflix(object):
VERSION = 'v0.4'
VERSION = 'v0.5.1'

# 超时秒数,包括隐式等待和显式等待
TIMEOUT = 23
Expand Down Expand Up @@ -302,9 +302,7 @@ def __forgot_password(self, netflix_username: str):

time.sleep(2)

self.click_forgot_pwd_btn()

self.handle_unknown_error_alert(self.click_forgot_pwd_btn, 12)
self.handle_click_events(self.click_forgot_pwd_btn, max_num_of_attempts=12)

# 直到页面显示已发送邮件
logger.debug('检测是否已到送信完成画面')
Expand Down Expand Up @@ -355,9 +353,7 @@ def __reset_password(self, curr_netflix_password: str, new_netflix_password: str

time.sleep(1)

self.click_submit_btn()

self.handle_unknown_error_alert(self.click_submit_btn)
self.handle_click_events(self.click_submit_btn)

return self.__pwd_change_result()
except Exception as e:
Expand Down Expand Up @@ -390,42 +386,107 @@ def click_submit_btn(self):
"""
self.driver.find_element_by_id('btn-save').click()

def element_visibility_of(self, xpath: str) -> WebElement or None:
def element_visibility_of(self, xpath: str, verify_val: bool = False,
max_num_of_attempts: int = 3, el_wait_time: int = 2) -> WebElement or None:
"""
元素是否存在且可见
适用于在已经加载完的网页做检测,可见且存在则返回元素,否则返回 None
:param xpath:
:param verify_val: 如果传入 True,则验证元素是否有值,或者 inner HTML 不为空,并作为关联条件
:param max_num_of_attempts: 最大尝试次数,由于有的元素的值可能是异步加载的,需要多次尝试是否能获取到值,每次获取间隔休眠次数秒
:param el_wait_time: 等待时间,查找元素最多等待多少秒,默认 2 秒
:return:
"""
try:
self.driver.implicitly_wait(2)

el = self.driver.find_element_by_xpath(xpath)
start_time = time.time()
while True:
if time.time() - start_time > el_wait_time:
logger.warning(f'查找元素 {xpath} 耗时超过 {el_wait_time} 秒')

return None

try:
# 此处只为找到元素,如果下面不需要验证元素是否有值的话,则使用此处找到的元素
# 否则下面验值逻辑会重新找到该元素以使用,此处的 el 会被覆盖
el = self.driver.find_element_by_xpath(xpath)

break
except Exception:
pass

num = 0
while True:
if not verify_val:
break

# 需要每次循环找到此元素,以确定元素的值是否发生变化
el = self.driver.find_element_by_xpath(xpath)

if el.tag_name == 'input':
val = el.get_attribute('value')
if val and len(val) > 0:
break
elif el.text != '':
break

# 多次尝试无果则放弃
if num > max_num_of_attempts:
break
num += 1

time.sleep(num)

return el if EC.visibility_of(el) else None
except Exception:
return None
finally:
self.driver.implicitly_wait(Netflix.TIMEOUT)

def has_unknown_error_alert(self) -> bool:
def has_unknown_error_alert(self, error_el_xpath: str) -> bool:
"""
Netflix 提醒页面出现未知错误
页面提示未知错误
:return:
"""
error_tips_el = self.element_visibility_of('//div[@class="ui-message-contents"]')

error_tips_el = self.element_visibility_of(error_el_xpath, True)
if error_tips_el:
# 密码修改成功画面的提示语与错误提示语共用的同一个元素,防止误报
if 'YourAccount?confirm=password' in self.driver.current_url or 'Your password has been changed' in error_tips_el.text:
return False

logger.warning('页面出现未知错误提醒,提醒内容为 ' + error_tips_el.text)
logger.warning(f'页面出现未知错误:{error_tips_el.text}')

return True

return False

def handle_click_events(self, func, error_el_xpath='//div[@class="ui-message-contents"]',
max_num_of_attempts: int = 10):
"""
处理点击事件
在某些画面点击提交的时候,有可能报未知错误,需要稍等片刻再点击才正常
:param func:
:param max_num_of_attempts:
:return:
"""
func()

num = 0
while True:
if self.has_unknown_error_alert(error_el_xpath):
func()

if num >= max_num_of_attempts:
raise Exception('处理未知错误失败')
num += 1

logger.info(f'程式将休眠 {num} 秒后重试点击动作')
time.sleep(num)
else:
break

def handle_unknown_error_alert(self, func, max_try: int = 10):
"""
处理 Netflix 未知异常
Expand Down Expand Up @@ -467,9 +528,8 @@ def __reset_password_via_mail(self, reset_url: str, new_netflix_password: str) -
self.driver.get(reset_url)

self.input_pwd(new_netflix_password)
self.click_submit_btn()

self.handle_unknown_error_alert(self.click_submit_btn)
self.handle_click_events(self.click_submit_btn)

# 如果奈飞提示密码曾经用过,则应该先改为随机密码,然后再改回来
pwd_error_tips = self.element_visibility_of('//div[@data-uia="field-newPassword+error"]')
Expand All @@ -479,9 +539,8 @@ def __reset_password_via_mail(self, reset_url: str, new_netflix_password: str) -

random_pwd = self.gen_random_pwd()
self.input_pwd(random_pwd)
self.click_submit_btn()

self.handle_unknown_error_alert(self.click_submit_btn)
self.handle_click_events(self.click_submit_btn)

if not self.__pwd_change_result():
return False
Expand Down
Binary file added resources/Netflix_Logo_RGB.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 55c917d

Please sign in to comment.