├── requirements.txt
├── .github
└── workflows
│ ├── love_heart_macos.yml
│ ├── love_heart_ubuntu.yml
│ ├── love_heart_windows.yml
│ ├── daily_sign.yml
│ ├── heart_break.yml
│ ├── heart_break2.yml
│ ├── wechat_msg.yml
│ └── weather_report.yml
├── daily_sign.py
├── LICENSE
├── wechat_msg.py
├── README.md
├── heart_break2.py
├── heart_break.py
├── weather_report.py
└── love_heart.py
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 | bs4
3 | html5lib
4 |
--------------------------------------------------------------------------------
/.github/workflows/love_heart_macos.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 画爱心macos版
5 |
6 | on:
7 | workflow_dispatch:
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | pyinstaller-build:
14 | runs-on: macos-latest
15 | steps:
16 | - name: Create Executable
17 | uses: sayyid5416/pyinstaller@v1
18 | with:
19 | python_ver: '3.12'
20 | spec: 'love_heart.py'
21 | upload_exe_with_name: 'love_heart'
22 | options: --onefile, --name "love_heart", --windowed,
23 |
--------------------------------------------------------------------------------
/.github/workflows/love_heart_ubuntu.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 画爱心Ubuntu版
5 |
6 | on:
7 | workflow_dispatch:
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | pyinstaller-build:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Create Executable
17 | uses: sayyid5416/pyinstaller@v1
18 | with:
19 | python_ver: '3.12'
20 | spec: 'love_heart.py'
21 | upload_exe_with_name: 'love_heart'
22 | options: --onefile, --name "love_heart", --windowed,
23 |
--------------------------------------------------------------------------------
/.github/workflows/love_heart_windows.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 画爱心Windows版
5 |
6 | on:
7 | workflow_dispatch:
8 |
9 | permissions:
10 | contents: read
11 |
12 | jobs:
13 | pyinstaller-build:
14 | runs-on: windows-latest
15 | steps:
16 | - name: Create Executable
17 | uses: sayyid5416/pyinstaller@v1
18 | with:
19 | python_ver: '3.12'
20 | spec: 'love_heart.py'
21 | upload_exe_with_name: 'love_heart'
22 | options: --onefile, --name "love_heart", --windowed,
23 |
--------------------------------------------------------------------------------
/.github/workflows/daily_sign.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 签到薅羊毛
5 |
6 | on:
7 | schedule:
8 | # 此处是UTC时间,对应北京时间早八点
9 | - cron : '00 00 * * *'
10 | workflow_dispatch:
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | build:
17 |
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | - uses: actions/checkout@v3
22 | - name: Set up Python 3.12
23 | uses: actions/setup-python@v3
24 | with:
25 | python-version: "3.12"
26 | - name: Install dependencies
27 | run: |
28 | python -m pip install --upgrade pip
29 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
30 | - name: Run weather Report
31 | run: |
32 | python daily_sign.py
33 | env:
34 | JD_COOKIE: ${{ secrets.JD_COOKIE }}
35 |
--------------------------------------------------------------------------------
/daily_sign.py:
--------------------------------------------------------------------------------
1 | import os
2 | import requests
3 |
4 | cookie = os.environ.get("JD_COOKIE")
5 |
6 | url = ("https://api.m.jd.com/client.action?functionId=signBeanAct&body=%7B%22fp%22%3A%22-1%22%2C%22shshshfp%22%3A%22-1"
7 | "%22%2C%22shshshfpa%22%3A%22-1%22%2C%22referUrl%22%3A%22-1%22%2C%22userAgent%22%3A%22-1%22%2C%22jda%22%3A%22-1"
8 | "%22%2C%22rnVersion%22%3A%223.9%22%7D&appid=ld&client=apple&clientVersion=10.0.4&networkType=wifi&osVersion=14"
9 | ".8.1&uuid=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6&openudid=3acd1f6361f86fc0a1bc23971b2e7bbe6197afb6&jsonp"
10 | "=jsonp_1645885800574_58482")
11 |
12 | headers = {"Connection": 'keep-alive',
13 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
14 | "Cache-Control": 'no-cache',
15 | "User-Agent": "okhttp/3.12.1;jdmall;android;version/10.3.4;build/92451;",
16 | "accept": "*/*",
17 | "connection": "Keep-Alive",
18 | "Accept-Encoding": "gzip,deflate",
19 | "Cookie": cookie
20 | }
21 |
22 | response = requests.post(url=url, headers=headers)
23 | print(response.text)
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 TechShrimp技术爬爬虾
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/heart_break.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 心跳测试
5 |
6 | on:
7 | schedule:
8 | # 设置启动时间,为 UTC 时间, UTC23点 对应北京时间早7点
9 | - cron : '15 * * * *'
10 | workflow_dispatch:
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | build:
17 |
18 | runs-on: ubuntu-latest
19 | env:
20 | TZ: Asia/Shanghai
21 | steps:
22 | - uses: actions/checkout@v3
23 | - name: Set up Python 3.12
24 | uses: actions/setup-python@v3
25 | with:
26 | python-version: "3.12"
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
31 | - name: Run heart break
32 | run: |
33 | python heart_break.py
34 | env:
35 | TARGET_URL: ${{ secrets.TARGET_URL }}
36 | ORIGIN_URL: ${{ secrets.ORIGIN_URL }}
37 | REFERER_URL: ${{ secrets.REFERER_URL }}
38 |
--------------------------------------------------------------------------------
/.github/workflows/heart_break2.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 心跳测试2
5 |
6 | on:
7 | schedule:
8 | # 设置启动时间,为 UTC 时间, UTC23点 对应北京时间早7点
9 | - cron : '45 * * * *'
10 | workflow_dispatch:
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | build:
17 |
18 | runs-on: ubuntu-latest
19 | env:
20 | TZ: Asia/Shanghai
21 | steps:
22 | - uses: actions/checkout@v3
23 | - name: Set up Python 3.12
24 | uses: actions/setup-python@v3
25 | with:
26 | python-version: "3.12"
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
31 | - name: Run heart break 2
32 | run: |
33 | python heart_break2.py
34 | env:
35 | TARGET_URL2: ${{ secrets.TARGET_URL2 }}
36 | ORIGIN_URL: ${{ secrets.ORIGIN_URL }}
37 | REFERER_URL: ${{ secrets.REFERER_URL }}
38 |
--------------------------------------------------------------------------------
/.github/workflows/wechat_msg.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 微信消息推送
5 |
6 | on:
7 | schedule:
8 | # 设置启动时间,为 UTC 时间, UTC23点 对应北京时间早7点
9 | - cron : '0 5 * * *'
10 | workflow_dispatch:
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | build:
17 |
18 | runs-on: ubuntu-latest
19 | env:
20 | TZ: Asia/Shanghai
21 | steps:
22 | - uses: actions/checkout@v3
23 | - name: Set up Python 3.12
24 | uses: actions/setup-python@v3
25 | with:
26 | python-version: "3.12"
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
31 | - name: Run wechat send message
32 | run: |
33 | python wechat_msg.py
34 | env:
35 | USERID: ${{ secrets.USERID }}
36 | AGENTID: ${{ secrets.AGENTID }}
37 | CORPID: ${{ secrets.CORPID }}
38 | CORPSECRET: ${{ secrets.CORPSECRET }}
39 |
--------------------------------------------------------------------------------
/.github/workflows/weather_report.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3 |
4 | name: 天气预报推送
5 |
6 | on:
7 | schedule:
8 | # 设置启动时间,为 UTC 时间, UTC23点 对应北京时间早7点
9 | - cron : '00 23 * * *'
10 | workflow_dispatch:
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | build:
17 |
18 | runs-on: ubuntu-latest
19 | env:
20 | TZ: Asia/Shanghai
21 | steps:
22 | - uses: actions/checkout@v3
23 | - name: Set up Python 3.12
24 | uses: actions/setup-python@v3
25 | with:
26 | python-version: "3.12"
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
31 | - name: Run weather Report
32 | run: |
33 | python weather_report.py
34 | env:
35 | APP_ID: ${{ secrets.APP_ID }}
36 | APP_SECRET: ${{ secrets.APP_SECRET }}
37 | OPEN_ID: ${{ secrets.OPEN_ID }}
38 | TEMPLATE_ID: ${{ secrets.TEMPLATE_ID }}
39 |
--------------------------------------------------------------------------------
/wechat_msg.py:
--------------------------------------------------------------------------------
1 | # 安装依赖 pip3 install requests html5lib bs4 schedule
2 | import os
3 | import requests
4 | import json
5 | import datetime
6 |
7 | # 从测试号信息获取
8 | userid = os.environ.get("USERID")
9 | agentid = os.environ.get("AGENTID")
10 | corpid = os.environ.get("CORPID")
11 | corpsecret = os.environ.get("CORPSECRET")
12 |
13 |
14 |
15 |
16 | class WeChatNotify:
17 |
18 | def __init__(self):
19 | pass
20 |
21 | def send_message_via_wechat(self, _message): # 默认发送给自己
22 |
23 | response = requests.get(
24 | f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}")
25 | data = json.loads(response.text)
26 | access_token = data['access_token']
27 |
28 | json_dict = {
29 | "touser": userid,
30 | "msgtype": "text",
31 | "agentid": agentid,
32 | "text": {
33 | "content": _message
34 | },
35 | "safe": 0,
36 | "enable_id_trans": 0,
37 | "enable_duplicate_check": 0,
38 | "duplicate_check_interval": 1800
39 | }
40 | json_str = json.dumps(json_dict)
41 | response_send = requests.post(f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}",
42 | data=json_str)
43 | return json.loads(response_send.text)['errmsg'] == 'ok'
44 |
45 |
46 |
47 | def main():
48 | wechat = WeChatNotify()
49 | wechat.send_message_via_wechat("Hello, World! From github actions.{}".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
50 |
51 | if __name__ == '__main__':
52 | main()
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Github Action功能样例
2 |
3 | 原理:使用Github Action功能,运行python程序,实现无服务器的免费任务,比如天气推送,薅羊毛,签到
4 |
5 |
6 | ## Part1 构建画爱心为可执行程序
7 | Fork本项目
8 |
9 | 构架Windows 可执行程序:
10 | Actions-->画爱心Windows版-->run work flow-->结束后查看结果
11 | -->Artifacts-->下载love_heart
12 |
13 | 构架Ubuntu 可执行程序:
14 | Actions-->画爱心Ubuntu版-->run work flow-->结束后查看结果
15 | -->Artifacts-->下载love_heart
16 |
17 | 构架MacOS 可执行程序:
18 | Actions-->画爱心MacOS版-->run work flow-->结束后查看结果
19 | -->Artifacts-->下载love_heart
20 |
21 |
22 | ## Part2 天气推送
23 |
24 | ### 申请公众号测试账户
25 |
26 | 使用微信扫码即可
27 | https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
28 |
29 | 进入页面以后我们来获取到这四个值
30 | #### appID appSecret openId template_id
31 | 
32 |
33 | 想让谁收消息,谁就用微信扫二维码,然后出现在用户列表,获取微信号(openId)
34 | 
35 |
36 | 新增测试模板获得 template_id(模板ID)
37 | 
38 |
39 | 模板标题随便填,模板内容如下,可以根据需求自己定制
40 |
41 | 模板内容:
42 | ```copy
43 | 今天:{{date.DATA}}
44 | 地区:{{region.DATA}}
45 | 天气:{{weather.DATA}}
46 | 气温:{{temp.DATA}}
47 | 风向:{{wind_dir.DATA}}
48 | 对你说的话:{{today_note.DATA}}
49 | ```
50 |
51 | ### 项目配置
52 | Fork本项目
53 | 进入自己项目的Settings ----> Secrets and variables ---> Actions --> New repository secret
54 | 配置好以下四个值(见上文)
55 |
56 |
57 |
58 | 进入自己项目的Action ----> 天气预报推送 ---> weather_report.yml --> 修改cron表达式的执行时间
59 |
60 |
61 | ## Part3 签到薅羊毛
62 | Fork本项目
63 | 网页上打开:www.jd.com/ 再按F12打开控制台,再点击切换模式,切换到手机模式,刷新一下页面。如图所示
64 | 
65 | 在网络->m.jd.com找到Cookie
66 |
67 |
68 |
69 | 将其填入 Settings ----> Secrets and variables ---> Actions --> New repository secret -->新增JD_COOKIE
70 |
71 |
72 | 进入自己项目的Action ----> 签到薅羊毛 ---> daily_sign.yml --> 修改cron表达式的执行时间
73 |
74 | ## Part 4 定时发送微信消息
75 |
76 | wechat_msg.py
77 |
78 | 设定cronjob时间,发布微信消息
--------------------------------------------------------------------------------
/heart_break2.py:
--------------------------------------------------------------------------------
1 | import threading
2 | import requests
3 | import json
4 | import os
5 |
6 | url = os.environ.get('TARGET_URL2')
7 | ORIGIN_URL = os.environ.get("ORIGIN_URL")
8 | REFERER_URL = os.environ.get("REFERER_URL")
9 |
10 |
11 | payload = json.dumps({
12 | "output": "..graph.figure...grid-result-detail-table.data...grid-eval-text.children..",
13 | "outputs": [
14 | {
15 | "id": "graph",
16 | "property": "figure"
17 | },
18 | {
19 | "id": "grid-result-detail-table",
20 | "property": "data"
21 | },
22 | {
23 | "id": "grid-eval-text",
24 | "property": "children"
25 | }
26 | ],
27 | "inputs": [
28 | {
29 | "id": "grid-button",
30 | "property": "nClicks",
31 | "value": 2
32 | }
33 | ],
34 | "changedPropIds": [
35 | "grid-button.nClicks"
36 | ],
37 | "state": [
38 | {
39 | "id": "grid-code",
40 | "property": "value",
41 | "value": "128143"
42 | },
43 | {
44 | "id": "date-picker-range",
45 | "property": "start_date",
46 | "value": "2021-08-15"
47 | },
48 | {
49 | "id": "date-picker-range",
50 | "property": "end_date",
51 | "value": "2022-08-15"
52 | },
53 | {
54 | "id": "grid-count",
55 | "property": "value",
56 | "value": 20
57 | },
58 | {
59 | "id": "grid-type",
60 | "property": "value",
61 | "value": "line"
62 | },
63 | {
64 | "id": "grid-c-rate",
65 | "property": "value",
66 | "value": 0.00005
67 | },
68 | {
69 | "id": "stop-on-top",
70 | "property": "value"
71 | },
72 | {
73 | "id": "grid-range",
74 | "property": "value",
75 | "value": [
76 | 100,
77 | 140
78 | ]
79 | }
80 | ]
81 | })
82 | headers = {
83 | 'accept': 'application/json',
84 | 'accept-language': 'zh,en;q=0.9,en-US;q=0.8,zh-CN;q=0.7,zh-TW;q=0.6',
85 | 'cache-control': 'no-cache',
86 | 'content-type': 'application/json',
87 | 'cookie': 'sl-session=Xnyib1wdeWcfqqilNWwh3g==; Hm_lvt_77cc3540511b0ae5a479b7d7f0994547=1733414758,1735904241; HMACCOUNT=8144A39C4F4A22E9; Hm_lpvt_77cc3540511b0ae5a479b7d7f0994547=1735906918; session=.eJyrVspMSc0rySyp1EssLcmIL6ksSFWyyivNydFByGSmQIRqAZu4EWc.Z3fsqQ.NUeLqedmtGwo-_trvaEisBQip80; session=.eJyrVspMSc0rySyp1EssLcmIL6ksSFWyyivNydFByGSmQIRqAZu4EWc.Z3fXHA.FuMb2586X2komaVS7gHtc551DSM',
88 | 'origin': ORIGIN_URL,
89 | 'pragma': 'no-cache',
90 | 'priority': 'u=1, i',
91 | 'referer': REFERER_URL,
92 | 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
93 | 'sec-ch-ua-mobile': '?0',
94 | 'sec-ch-ua-platform': '"Windows"',
95 | 'sec-fetch-dest': 'empty',
96 | 'sec-fetch-mode': 'cors',
97 | 'sec-fetch-site': 'same-origin',
98 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
99 | 'x-csrftoken': 'undefined'
100 | }
101 |
102 |
103 | def send_request():
104 | try:
105 | response = requests.request(
106 | "POST", url, headers=headers, data=payload, timeout=10)
107 | print(response.text)
108 | except Exception as e:
109 | print(e)
110 |
111 |
112 | thread_list = []
113 | for i in range(100):
114 | t = threading.Thread(target=send_request)
115 | t.start()
116 | thread_list.append(t)
117 |
118 |
119 | for t in thread_list:
120 | t.join()
121 |
122 | print("done")
123 |
--------------------------------------------------------------------------------
/heart_break.py:
--------------------------------------------------------------------------------
1 | import threading
2 | import requests
3 | import json
4 | import os
5 | import time
6 |
7 | url = os.environ.get('TARGET_URL')
8 | ORIGIN_URL = os.environ.get("ORIGIN_URL")
9 | REFERER_URL = os.environ.get("REFERER_URL")
10 |
11 | payload = json.dumps({
12 | "output": "market-board-grid-container.children",
13 | "outputs": {
14 | "id": "market-board-grid-container",
15 | "property": "children"
16 | },
17 | "inputs": [
18 | {
19 | "id": "market-board-layouts-restore",
20 | "property": "data",
21 | "value": [
22 | {
23 | "w": 12,
24 | "h": 6,
25 | "x": 0,
26 | "y": 0,
27 | "i": "scope_graph",
28 | "moved": False,
29 | "static": False
30 | },
31 | {
32 | "w": 6,
33 | "h": 4,
34 | "x": 0,
35 | "y": 6,
36 | "i": "up_or_down_graph",
37 | "moved": False,
38 | "static": False
39 | },
40 | {
41 | "w": 6,
42 | "h": 4,
43 | "x": 6,
44 | "y": 6,
45 | "i": "agg_table",
46 | "moved": False,
47 | "static": False
48 | },
49 | {
50 | "w": 12,
51 | "h": 5,
52 | "x": 0,
53 | "y": 10,
54 | "i": "treemap",
55 | "moved": False,
56 | "static": False
57 | }
58 | ]
59 | }
60 | ],
61 | "changedPropIds": [
62 | "market-board-layouts-restore.data"
63 | ]
64 | })
65 |
66 | headers = {
67 | 'accept': 'application/json',
68 | 'accept-language': 'zh,en;q=0.9,en-US;q=0.8,zh-CN;q=0.7,zh-TW;q=0.6',
69 | 'cache-control': 'no-cache',
70 | 'content-type': 'application/json',
71 | 'cookie': 'sl-session=Xnyib1wdeWcfqqilNWwh3g==; Hm_lvt_77cc3540511b0ae5a479b7d7f0994547=1733414758,1735904241; HMACCOUNT=8144A39C4F4A22E9; Hm_lpvt_77cc3540511b0ae5a479b7d7f0994547=1735906918; session=.eJyrVspMSc0rySyp1EssLcmIL6ksSFWyyivNydFByGSmQIRqAZu4EWc.Z3fWUg.dnGBgW2aZwgaPYStmdMb6r2xngE; session=.eJyrVspMSc0rySyp1EssLcmIL6ksSFWyyivNydFByGSmQIRqAZu4EWc.Z3fXHA.FuMb2586X2komaVS7gHtc551DSM',
72 | 'origin': ORIGIN_URL,
73 | 'pragma': 'no-cache',
74 | 'priority': 'u=1, i',
75 | 'referer': REFERER_URL,
76 | 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
77 | 'sec-ch-ua-mobile': '?0',
78 | 'sec-ch-ua-platform': '"Windows"',
79 | 'sec-fetch-dest': 'empty',
80 | 'sec-fetch-mode': 'cors',
81 | 'sec-fetch-site': 'same-origin',
82 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
83 | 'x-csrftoken': 'undefined'
84 | }
85 |
86 |
87 | def send_request():
88 | try:
89 | response = requests.request(
90 | "POST", url, headers=headers, data=payload, timeout=10)
91 | print(response.text)
92 | except Exception as e:
93 | print(e)
94 |
95 |
96 | thread_list = []
97 | for i in range(100):
98 | t = threading.Thread(target=send_request)
99 | t.start()
100 | thread_list.append(t)
101 |
102 |
103 | for t in thread_list:
104 | t.join()
105 | print("done")
106 |
--------------------------------------------------------------------------------
/weather_report.py:
--------------------------------------------------------------------------------
1 | # 安装依赖 pip3 install requests html5lib bs4 schedule
2 | import os
3 | import requests
4 | import json
5 | from bs4 import BeautifulSoup
6 |
7 | # 从测试号信息获取
8 | appID = os.environ.get("APP_ID")
9 | appSecret = os.environ.get("APP_SECRET")
10 | # 收信人ID即 用户列表中的微信号
11 | openId = os.environ.get("OPEN_ID")
12 | # 天气预报模板ID
13 | weather_template_id = os.environ.get("TEMPLATE_ID")
14 |
15 | def get_weather(my_city):
16 | urls = ["http://www.weather.com.cn/textFC/hb.shtml",
17 | "http://www.weather.com.cn/textFC/db.shtml",
18 | "http://www.weather.com.cn/textFC/hd.shtml",
19 | "http://www.weather.com.cn/textFC/hz.shtml",
20 | "http://www.weather.com.cn/textFC/hn.shtml",
21 | "http://www.weather.com.cn/textFC/xb.shtml",
22 | "http://www.weather.com.cn/textFC/xn.shtml"
23 | ]
24 | for url in urls:
25 | resp = requests.get(url)
26 | text = resp.content.decode("utf-8")
27 | soup = BeautifulSoup(text, 'html5lib')
28 | div_conMidtab = soup.find("div", class_="conMidtab")
29 | tables = div_conMidtab.find_all("table")
30 | for table in tables:
31 | trs = table.find_all("tr")[2:]
32 | for index, tr in enumerate(trs):
33 | tds = tr.find_all("td")
34 | # 这里倒着数,因为每个省会的td结构跟其他不一样
35 | city_td = tds[-8]
36 | this_city = list(city_td.stripped_strings)[0]
37 | if this_city == my_city:
38 |
39 | high_temp_td = tds[-5]
40 | low_temp_td = tds[-2]
41 | weather_type_day_td = tds[-7]
42 | weather_type_night_td = tds[-4]
43 | wind_td_day = tds[-6]
44 | wind_td_day_night = tds[-3]
45 |
46 | high_temp = list(high_temp_td.stripped_strings)[0]
47 | low_temp = list(low_temp_td.stripped_strings)[0]
48 | weather_typ_day = list(weather_type_day_td.stripped_strings)[0]
49 | weather_type_night = list(weather_type_night_td.stripped_strings)[0]
50 |
51 | wind_day = list(wind_td_day.stripped_strings)[0] + list(wind_td_day.stripped_strings)[1]
52 | wind_night = list(wind_td_day_night.stripped_strings)[0] + list(wind_td_day_night.stripped_strings)[1]
53 |
54 | # 如果没有白天的数据就使用夜间的
55 | temp = f"{low_temp}——{high_temp}摄氏度" if high_temp != "-" else f"{low_temp}摄氏度"
56 | weather_typ = weather_typ_day if weather_typ_day != "-" else weather_type_night
57 | wind = f"{wind_day}" if wind_day != "--" else f"{wind_night}"
58 | return this_city, temp, weather_typ, wind
59 |
60 |
61 | def get_access_token():
62 | # 获取access token的url
63 | url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}' \
64 | .format(appID.strip(), appSecret.strip())
65 | response = requests.get(url).json()
66 | print(response)
67 | access_token = response.get('access_token')
68 | return access_token
69 |
70 |
71 | def get_daily_love():
72 | # 每日一句情话
73 | url = "https://api.lovelive.tools/api/SweetNothings/Serialization/Json"
74 | r = requests.get(url)
75 | all_dict = json.loads(r.text)
76 | sentence = all_dict['returnObj'][0]
77 | daily_love = sentence
78 | return daily_love
79 |
80 |
81 | def send_weather(access_token, weather):
82 | # touser 就是 openID
83 | # template_id 就是模板ID
84 | # url 就是点击模板跳转的url
85 | # data就按这种格式写,time和text就是之前{{time.DATA}}中的那个time,value就是你要替换DATA的值
86 |
87 | import datetime
88 | today = datetime.date.today()
89 | today_str = today.strftime("%Y年%m月%d日")
90 |
91 | body = {
92 | "touser": openId.strip(),
93 | "template_id": weather_template_id.strip(),
94 | "url": "https://weixin.qq.com",
95 | "data": {
96 | "date": {
97 | "value": today_str
98 | },
99 | "region": {
100 | "value": weather[0]
101 | },
102 | "weather": {
103 | "value": weather[2]
104 | },
105 | "temp": {
106 | "value": weather[1]
107 | },
108 | "wind_dir": {
109 | "value": weather[3]
110 | },
111 | "today_note": {
112 | "value": get_daily_love()
113 | }
114 | }
115 | }
116 | url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}'.format(access_token)
117 | print(requests.post(url, json.dumps(body)).text)
118 |
119 |
120 |
121 | def weather_report(this_city):
122 | # 1.获取access_token
123 | access_token = get_access_token()
124 | # 2. 获取天气
125 | weather = get_weather(this_city)
126 | print(f"天气信息: {weather}")
127 | # 3. 发送消息
128 | send_weather(access_token, weather)
129 |
130 |
131 |
132 | if __name__ == '__main__':
133 | weather_report("淄博")
--------------------------------------------------------------------------------
/love_heart.py:
--------------------------------------------------------------------------------
1 | # 版权https://github.com/royalneverwin/beating-heart
2 |
3 | from tkinter import * # Python 实现GUI界面的包
4 | from math import sin, cos, pi, log
5 | import random
6 | import time
7 |
8 | CANVAS_WIDTH = 640
9 | CANVAS_HEIGHT = 480
10 | CANVAS_CENTER_X = CANVAS_WIDTH / 2
11 | CANVAS_CENTER_Y = CANVAS_HEIGHT / 2
12 | IMAGE_ENLARGE = 11
13 |
14 |
15 | def scatter_inside(x, y, beta=0.15): # log scatter & scatter inside
16 | ratiox = - beta * log(random.random()) #*** can modify ***#
17 | ratioy = - beta * log(random.random())
18 | dx = ratiox * (x - CANVAS_CENTER_X)
19 | dy = ratioy * (y - CANVAS_CENTER_Y)
20 | return x - dx, y - dy
21 |
22 |
23 | def heart_function(t, enlarge_ratio: float = IMAGE_ENLARGE):
24 | # heart function
25 | x = 16 * (sin(t)**3)
26 | y = -(13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t))
27 |
28 | # enlarge
29 | x *= enlarge_ratio
30 | y *= enlarge_ratio
31 |
32 | # shift to the center of canvas
33 | x += CANVAS_CENTER_X
34 | y += CANVAS_CENTER_Y
35 |
36 | return int(x), int(y)
37 |
38 | def shrink(x, y, ratio):
39 | sk_range = -1 / ((x-CANVAS_CENTER_X) ** 2 + (y-CANVAS_CENTER_Y) ** 2)
40 | dx = ratio * sk_range * (x-CANVAS_CENTER_X)
41 | dy = ratio * sk_range * (y-CANVAS_CENTER_Y)
42 | return x - dx, y - dy
43 |
44 |
45 | class Heart:
46 | def __init__(self, frame):
47 | self.points = set()
48 | self.edge_points = set()
49 | self.inside_points = set()
50 | self.all_points = {}
51 | self.build(2000) #*** can modify ***#
52 | self.frame = frame
53 | for f in range(frame): # pre calculate
54 | self.calc(f)
55 |
56 | # for halo
57 | self.random_halo = 1000
58 |
59 |
60 |
61 | def build(self, number):
62 | # randomly find 'number' points on the heart curve
63 | for _ in range(number):
64 | t = random.uniform(0, 2 * pi) # t = angle
65 | x, y = heart_function(t)
66 | x, y = shrink(x, y, -1000)
67 | self.points.add((int(x), int(y)))
68 |
69 | # randomly find points on the edge
70 | for px, py in self.points:
71 | for _ in range(3): #*** can modify ***#
72 | x, y = scatter_inside(px, py, 0.05) #*** can modify ***#
73 | self.edge_points.add((x, y))
74 |
75 | # randomly find points inside the heart
76 | pt_ls = list(self.points)
77 | for _ in range(4000): #*** can modify ***#
78 | x, y = random.choice(pt_ls) # choice need idx, and set has no idx, only list has
79 | x, y = scatter_inside(x, y) #*** can modify ***#
80 | self.inside_points.add((x, y))
81 |
82 |
83 | def cal_position(self, x, y, ratio): # calculate the position of points when beating
84 | # attention: the closer to the center, the bigger beating range point has
85 | bt_range = 1 / ((x-CANVAS_CENTER_X) ** 2 + (y-CANVAS_CENTER_Y) ** 2)
86 | dx = ratio * bt_range * (x-CANVAS_CENTER_X) + random.randint(-1, 1)
87 | dy = ratio * bt_range * (y-CANVAS_CENTER_Y) + random.randint(-1, 1)
88 | return x - dx, y - dy
89 |
90 |
91 | def calc(self, frame): # calculate points' position for different frame
92 | ratio = 800 * sin(frame / 10 * pi) #*** can modify ***# this is 30 fps
93 | all_pts = []
94 |
95 | # for halo
96 | halo_radius = int(4 + 6 * (1 + sin(self.frame / 10 * pi)))
97 | halo_number = int(3000 + 4000 * abs(sin(self.frame / 10 * pi) ** 2))
98 | heart_halo_point = set()
99 | for _ in range(halo_number):
100 | t = random.uniform(0, 2 * pi)
101 | x, y = heart_function(t, enlarge_ratio=11.6)
102 | x, y = shrink(x, y, halo_radius)
103 | if (x, y) not in heart_halo_point:
104 | # 处理新的点
105 | heart_halo_point.add((x, y))
106 | x += random.randint(-14, 14)
107 | y += random.randint(-14, 14)
108 | size = random.choice((1, 2, 2))
109 | all_pts.append((x, y, size))
110 |
111 | # on the curve
112 | for x, y in self.points:
113 | x, y = self.cal_position(x, y, ratio)
114 | size = random.randint(1, 3) #*** can modify ***#
115 | all_pts.append((x, y, size))
116 |
117 | # on the edge
118 | for x, y in self.edge_points:
119 | x, y = self.cal_position(x, y, ratio)
120 | size = random.randint(1, 2) #*** can modify ***#
121 | all_pts.append((x, y, size))
122 |
123 | # inside
124 | for x, y in self.inside_points:
125 | x, y = self.cal_position(x, y, ratio)
126 | size = random.randint(1, 2) #*** can modify ***#
127 | all_pts.append((x, y, size))
128 |
129 | self.all_points[frame] = all_pts
130 |
131 |
132 | def render(self, canvas, frame): # draw points
133 | for x, y, size in self.all_points[frame % self.frame]: # set operation
134 | canvas.create_rectangle(x, y, x+size, y+size, width=0, fill='#ff7171')
135 |
136 |
137 | def draw(root: Tk, canvas: Canvas, heart: Heart, frame=0):
138 | canvas.delete('all')
139 | heart.render(canvas, frame)
140 | root.after(30, draw, root, canvas, heart, frame+1)
141 |
142 |
143 | if __name__ == '__main__':
144 | root = Tk()
145 | root.title('漂亮宝贝一周年快乐')
146 | canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
147 | canvas.pack()
148 | heart = Heart(20)
149 | draw(root, canvas, heart)
150 | root.mainloop()
--------------------------------------------------------------------------------