Skip to content

Commit

Permalink
#18 Post in jietiandi forum automatically (#19)
Browse files Browse the repository at this point in the history
* Support login

* Finish all

* fix workflow: "./sign.py: Permission denied"

* test: "No module named 'ddddocr'"

* test: "No module named 'ddddocr'"

* test: "No module named 'ddddocr'"

* fix: "A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.0.0 as it may crash. To support both 1.x and 2.x"

* fix: "No module named 'ddddocr'"
  • Loading branch information
paigeman authored Jun 20, 2024
1 parent fffc7a3 commit 9af00c3
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 0 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/jietiandi-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: jietiandi-dev
on:
push:
branches:
- 18-post-in-jietiandi-forum-automatically
jobs:
dev:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
# This is the version of the action for setting up Python, not the Python version.
uses: actions/setup-python@v5
with:
# Semantic version range syntax or exact version of a Python version
python-version: '3.12'
- name: Install requirements
working-directory: jietiandi
run: pip3 install -r requirements.txt
- name: Sign
env:
USERNAME: ${{ secrets.JIETIANDI_USERNAME }}
PASSWORD: ${{ secrets.JIETIANDI_PASSWORD }}
run: |
chmod u+x sign.py
python ./sign.py
working-directory: jietiandi
- name: Post
env:
USERNAME: ${{ secrets.JIETIANDI_USERNAME }}
PASSWORD: ${{ secrets.JIETIANDI_PASSWORD }}
run: |
chmod u+x post.py
python ./post.py
working-directory: jietiandi

30 changes: 30 additions & 0 deletions .github/workflows/jietiandi-prod-post.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: jietiandi-prod-post
on:
push:
branches:
- main
schedule:
- cron: '0/12 1-4 * * *'
jobs:
post:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
# This is the version of the action for setting up Python, not the Python version.
uses: actions/setup-python@v5
with:
# Semantic version range syntax or exact version of a Python version
python-version: '3.x'
- name: Install requirements
run: pip3 install -r requirements.txt
working-directory: jietiandi
- name: Post
env:
USERNAME: ${{ secrets.JIETIANDI_USERNAME }}
PASSWORD: ${{ secrets.JIETIANDI_PASSWORD }}
run: |
chmod u+x post.py
python ./post.py
working-directory: jietiandi

30 changes: 30 additions & 0 deletions .github/workflows/jietiandi-prod-sign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: jietiandi-prod-sign
on:
push:
branches:
- main
schedule:
- cron: '0 23 * * *'
jobs:
sign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
# This is the version of the action for setting up Python, not the Python version.
uses: actions/setup-python@v5
with:
# Semantic version range syntax or exact version of a Python version
python-version: '3.x'
- name: Install requirements
run: pip3 install -r requirements.txt
working-directory: jietiandi
- name: Sign
env:
USERNAME: ${{ secrets.JIETIANDI_USERNAME }}
PASSWORD: ${{ secrets.JIETIANDI_PASSWORD }}
run: |
chmod u+x sign.py
python ./sign.py
working-directory: jietiandi

1 change: 1 addition & 0 deletions jietiandi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
168 changes: 168 additions & 0 deletions jietiandi/login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/python3

import pickle
from os import listdir
import sys
import logging
# import requests
import ddddocr
import re
from curl_cffi import requests

# 日志输出至控制台
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(filename)s %(funcName)s:line %(lineno)d %(levelname)s %(message)s")

class Login:
def __init__(self, hostname, username, password, questionid='0', answer=None, cookies_flag=True):
self.session = requests.Session()
self.session.headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'})
self.hostname = hostname
self.username = str(username)
self.password = str(password)

self.questionid = questionid
self.answer = answer
self.cookies_name = 'cookies.pk'
self.cookies_flag = cookies_flag
self.ocr = ddddocr.DdddOcr()


def form_hash(self):
rst = self.session.get(f'https://{self.hostname}/member.php?mod=logging&action=login').text
# logging.info(f'{rst}')
loginhash = re.search(r'<div id="main_messaqge_(.+?)">', rst).group(1)
formhash = re.search(r'<input type="hidden" name="formhash" value="(.+?)" />', rst).group(1)
logging.info(f'loginhash : {loginhash} , formhash : {formhash} ')
return loginhash, formhash

def verify_code_once(self):
rst = self.session.get(f'https://{self.hostname}/misc.php?mod=seccode&action=update&idhash=cSA&0.3701502461393815&modid=member::logging').text
update = re.search(r'update=(.+?)&idhash=', rst).group(1)

code_headers = {
'Accept': 'image/webp,image/apng,image/*,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'hostname': f'{self.hostname}',
'Referer': f'https://{self.hostname}/member.php?mod=logging&action=login',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
rst = self.session.get(f'https://{self.hostname}/misc.php?mod=seccode&update={update}&idhash=cSA',
headers=code_headers)

return self.ocr.classification(rst.content)


def verify_code(self,num = 10):
while num>0:
num -=1
code = self.verify_code_once()
verify_url = f'https://{self.hostname}/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash=cSA&secverify={code}'
res = self.session.get(verify_url).text

if 'succeed' in res:
logging.info('验证码识别成功,验证码:'+code)
return code
else:
logging.info('验证码识别失败,重新识别中...')

logging.error('验证码获取失败,请增加验证次数或检查当前验证码识别功能是否正常')
return ''

def account_login_without_verify(self):

loginhash, formhash = self.form_hash()
login_url = f'https://{self.hostname}/member.php?mod=logging&action=login&loginsubmit=yes&loginhash={loginhash}&inajax=1'
formData = {
'formhash': formhash,
'referer': f'https://{self.hostname}/',
'username': self.username,
'password': self.password,
}
login_rst = self.session.post(login_url, data=formData).text
if 'succeed' in login_rst:
logging.info('登陆成功')
return True
else:
logging.info('登陆失败,请检查账号或密码是否正确')
return False



def account_login(self):
try:
if self.account_login_without_verify():
return True
except Exception:
logging.error('存在验证码,登陆失败,准备获取验证码中', exc_info=True)

code = self.verify_code()
if code =='':
return False

loginhash, formhash = self.form_hash()
login_url = f'https://{self.hostname}/member.php?mod=logging&action=login&loginsubmit=yes&loginhash={loginhash}&inajax=1'
formData = {
'formhash': formhash,
'referer': f'https://{self.hostname}/',
'loginfield': self.username,
'username': self.username,
'password': self.password,
'questionid': self.questionid,
'answer': self.answer,
'cookietime': 2592000,
'seccodehash': 'cSA',
'seccodemodid': 'member::logging',
'seccodeverify': code, # verify code
}
login_rst = self.session.post(login_url, data=formData).text
if 'succeed' in login_rst:
logging.info('登陆成功')
return True
else:
logging.info('登陆失败,请检查账号或密码是否正确')
return False


def cookies_login(self):
if self.cookies_name in listdir():
try:
with open(self.cookies_name, 'rb') as f:
self.session.cookies.jar._cookies = pickle.load(f)
response = self.session.get(f'https://{self.hostname}/home.php?mod=space').text

if "退出" in response and "登录" not in response:
logging.info('从文件中恢复Cookie成功,跳过登录。')
return True
except Exception:
logging.warning('Cookie失效,使用账号密码登录。')
else:
logging.info('初次登录未发现Cookie,使用账号密码登录。')
return False


def go_home(self):
return self.session.get(f'https://{self.hostname}/forum.php').text

def main(self):

try:
if self.cookies_flag and self.cookies_login():
logging.info('成功使用cookies登录')
else:
self.account_login()
with open(self.cookies_name, 'wb') as f:
pickle.dump(self.session.cookies.jar._cookies, f)
logging.info('新的Cookie已保存。')

except Exception:
logging.error('失败,发生了一个错误!', exc_info=True)
sys.exit()


if __name__ == '__main__':
login = Login('','','')
login.main()
63 changes: 63 additions & 0 deletions jietiandi/post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/python3

import login

import logging
import re
import requests
import os
logging.basicConfig(level=logging.INFO ,format="%(asctime)s %(filename)s %(funcName)s:line %(lineno)d %(levelname)s %(message)s")


class Post:
def __init__(self, hostname, username, password, questionid='0', answer=None, cookies_flag=True,pub_url = ''):
self.hostname = hostname
if pub_url !='':
self.hostname = self.get_host(pub_url)

self.discuz_login = login.Login(self.hostname, username, password, questionid, answer, cookies_flag)

def login(self):
self.discuz_login.main()
self.session = self.discuz_login.session
self.formhash = self.get_formhash()

def get_formhash(self):
rst = self.session.get(f'https://{self.hostname}/forum.php?mod=viewthread&tid=2951721&extra=page%3D1').text
formhash = re.search(r'<input type="hidden" name="formhash" value="(.+?)" />', rst).group(1)
return formhash

def get_host(self,pub_url):
res = requests.get(pub_url)
res.encoding = "utf-8"
url = re.search(r'a href="https://(.+?)/".+?>.+?入口</a>', res.text)
if url != None:
url = url.group(1)
logging.info(f'获取到最新的论坛地址:https://{url}')
return url
else:
logging.error(f'获取失败,请检查发布页是否可用{pub_url}')
return self.hostname

def post(self):
post_url = f'https://{self.hostname}/forum.php?mod=post&action=reply&fid=294&tid=2951721&extra=page%3D1&replysubmit=yes&infloat=yes&handlekey=fastpost&inajax=1'
data = {
'message': 'ddddddddddddddddddd',
'formhash': self.formhash,
'usesig': 1,
'subject': ''
}
res = self.session.post(post_url, data=data).text
# logging.info(res)
if 'succeed' in res:
logging.info('回复发送成功')
else :
logging.error('回复发送失败')

if __name__ == '__main__':
hostname = 'jietiandi.net'
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
post = Post(hostname,username,password)
post.login()
post.post()
4 changes: 4 additions & 0 deletions jietiandi/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
curl_cffi==0.6.4
ddddocr==1.5.4
Requests==2.32.3
numpy==1.26.4
37 changes: 37 additions & 0 deletions jietiandi/sign.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/python3

import login
import logging
import re
import os

logging.basicConfig(level=logging.INFO ,format="%(asctime)s %(filename)s %(funcName)s:line %(lineno)d %(levelname)s %(message)s")

class Sign:
def __init__(self, hostname, username, password, questionid='0', answer=None, cookies_flag=True):
self.hostname = hostname
self.discuz_login = login.Login(self.hostname, username, password, questionid, answer, cookies_flag)

def login(self):
self.discuz_login.main()
self.session = self.discuz_login.session

def sign(self):
# 未来可以考虑直接用formhash拼接,目测是同一个formhash
rst = self.session.get(f'https://{self.hostname}/plugin.php?id=zqlj_sign').text
# logging.info(rst)
sign = re.search(r'a href="plugin.php\?id=zqlj_sign&sign=(.+?)".+?>.+?打卡</a>', rst).group(1)
rst = self.session.get(f'https://{self.hostname}/plugin.php?id=zqlj_sign&sign={sign}').text
# logging.info(rst)
if '已经打过卡' in rst:
logging.warning('已经打过卡')
else:
logging.info('打卡成功')

if __name__ == '__main__':
hostname = 'jietiandi.net'
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
sign = Sign(hostname,username,password)
sign.login()
sign.sign()

0 comments on commit 9af00c3

Please sign in to comment.