Files
test/体彩/竟彩足球结果-钉钉.py
2026-05-07 10:49:58 +08:00

231 lines
9.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime
import time
import hmac
import hashlib
import base64
import requests
import json
from lxml import etree
# ====================== 1. 钉钉机器人类(保持不变,修复中文编码) ======================
class DingDingRobot:
"""钉钉机器人消息发送类"""
def __init__(self, token, secret):
self.token = token
self.secret = secret
self.base_url = "https://oapi.dingtalk.com/robot/send"
def _sign(self):
timestamp = str(round(time.time() * 1000))
string_to_sign = f"{timestamp}\n{self.secret}"
hmac_code = hmac.new(
self.secret.encode('utf-8'),
string_to_sign.encode('utf-8'),
digestmod=hashlib.sha256
).digest()
sign = base64.b64encode(hmac_code).decode('utf-8')
return timestamp, sign
def _build_request_url(self):
timestamp, sign = self._sign()
url = f"{self.base_url}?access_token={self.token}&timestamp={timestamp}&sign={sign}"
return url
def build_markdown_data(self, title, text):
return {
"msgtype": "markdown",
"markdown": {"title": title, "text": text}
}
def send_message(self, data):
try:
url = self._build_request_url()
headers = {'Content-Type': 'application/json;charset=utf-8'} # 明确指定utf-8
response = requests.post(
url=url,
data=json.dumps(data, ensure_ascii=False), # 关键:保留中文
headers=headers
)
resp_json = response.json()
if response.status_code == 200 and resp_json.get("errcode") == 0:
return True, "消息发送成功"
else:
return False, f"消息发送失败:{resp_json.get('errmsg', '未知错误')}"
except Exception as e:
return False, f"发送异常:{str(e)}"
# ====================== 2. 赛果转换工具函数 ======================
def saiguo(saiguo1):
"""将数字赛果转为中文(3→胜,1→平,0→负)"""
saiguo_map = {'3': '', '1': '', '0': ''}
return saiguo_map.get(saiguo1.strip(), '-')
# ====================== 3. 安全提取XPath文本(核心修复:避免索引报错) ======================
def safe_xpath(elem, xpath_expr):
"""安全提取XPath文本,空值返回'-'"""
res = elem.xpath(xpath_expr)
return res[0].strip() if res and res[0].strip() else '-'
# ====================== 4. 获取html数据(修复日期格式) ======================
def req(yesterday_str, today_str):
"""爬取竞彩开奖数据,修复日期格式为YYYYMMDD"""
url = 'https://www.okooo.com/jingcai/kaijiang/'
headers = {
'user-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
'Referer': 'https://www.okooo.com/', # 增加Referer避免反爬
}
# 关键修复:StartDate/EndDate要求YYYYMMDD格式(无横线)
params = {
'LotteryType': 'SportteryWDL',
'StartDate': yesterday_str.replace('-', ''),
'EndDate': today_str.replace('-', ''),
}
try:
response = requests.get(url, headers=headers, params=params, timeout=10)
response.encoding = response.apparent_encoding # 自动识别编码
return response.text
except Exception as e:
print(f"爬取页面失败:{e}")
return ""
# ====================== 5. 结果处理成列表(核心修复:XPath安全提取+半全场分割) ======================
def jieguo_(html,today):
if not html:
return []
html_etree = etree.HTML(html)
# 修复:直接获取所有数据行,避免按results长度偏移
tr_list = html_etree.xpath('//table[@class="tableborder tableborder02"]//tr')
jieguo = []
# 遍历行(跳过前2行表头)
for tr_idx, tr in enumerate(tr_list):
if tr_idx < 2: # 跳过表头行(根据实际页面调整)
continue
# 提取半全场数据(修复分割逻辑)
saiguo_ = safe_xpath(tr, './td[17]/b/text()')
saiguo1 = '-'
if saiguo_ and '-' in saiguo_:
parts = saiguo_.split('-', 1) # 只分割一次
if len(parts) == 2:
a = saiguo(parts[0])
b = saiguo(parts[1])
saiguo1 = f"{a}-{b}"
# 安全提取所有字段(基于当前tr节点,避免全局XPath)
try:
data = {
'场次': safe_xpath(tr, './td[1]/text()'),
'联赛': safe_xpath(tr, './td[2]/span/text()'),
'时间': safe_xpath(tr, './td[3]/text()'),
'主队': safe_xpath(tr, './td[4]/a/text()'),
'客队': safe_xpath(tr, './td[5]/a/text()'),
'半场': safe_xpath(tr, './td[6]/text()'),
'全场': safe_xpath(tr, './td[7]/text()'),
'胜平负': saiguo(safe_xpath(tr, './td[8]/b/text()')),
'胜平负赔率': safe_xpath(tr, './td[9]/text()'),
'让球': safe_xpath(tr, './td[10]/span/text()'),
'让胜平负': saiguo(safe_xpath(tr, './td[11]/b/text()')),
'让胜平负赔率': safe_xpath(tr, './td[12]/text()'),
'比分': safe_xpath(tr, './td[13]/b/text()'),
'比分赔率': safe_xpath(tr, './td[14]/text()'),
'总进球': safe_xpath(tr, './td[15]/b/text()'),
'总进球赔率': safe_xpath(tr, './td[16]/text()'),
'半全场': saiguo1,
'半全场赔率': safe_xpath(tr, './td[18]/text()')
}
# 过滤空场次数据
weekday_cn = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"][today.weekday() - 1]
if data['场次'] != '-' and weekday_cn in data['场次']:
jieguo.append(data)
except Exception as e:
print(f"提取第{tr_idx}行数据失败:{e}")
continue
return jieguo
# ====================== 6. 生成Markdown表格(核心修复:去掉缩进,规范语法) ======================
def generate_markdown_table(data_list, table_headers=None):
"""生成钉钉兼容的Markdown表格(无缩进、语法规范)"""
if not data_list:
return "### 竞猜比赛结果\n暂无有效数据"
# 自定义表头(只保留你需要的字段)
if table_headers is None:
table_headers = {
'场次':' 场次 ',
'联赛':' 联赛 ',
"主队": " 主队 ",
'客队':' 客队 ',
"胜平负": " 胜平负 ",
"让胜平负": " 让胜平负 ",
"比分": " 比分 ",
"总进球": " 总进球 ",
"半全场": " 半全场 "
}
header_keys = list(table_headers.keys())
# 第一步:构建表头(无缩进!)
header_str = "| " + " | ".join([table_headers[key] for key in header_keys]) + " |"
# 第二步:构建分隔行(必须和表头列数一致)
separator_str = "| " + " | ".join(["---" for _ in header_keys]) + " |"
# 第三步:构建数据行
data_rows = []
for data in data_list:
row_values = [data.get(key, "-") for key in header_keys]
row_str = "| " + " | ".join(row_values) + " |"
data_rows.append(row_str)
data_rows_str = "\n".join(data_rows)
# 关键:拼接时去掉所有多余缩进/空格,行尾不要有多余空格
markdown_table = f"""### 竞猜比赛结果
{header_str}
{separator_str}
{data_rows_str}"""
return markdown_table
# ====================== 7. 主函数(修复日期格式+分批发送避免字数超限) ======================
def main():
# 1. 处理日期(统一为YYYY-MM-DD格式,再传给req函数处理)
today = datetime.date.today()
today_str = today.strftime('%Y-%m-%d')
yesterday = today - datetime.timedelta(days=1)
yesterday_str = yesterday.strftime("%Y-%m-%d")
# 2. 爬取数据
html = req(yesterday_str, today_str)
data = jieguo_(html,today)
if not data:
print("未爬取到有效数据")
return
# 3. 钉钉机器人配置(替换为你的实际token/secret
DING_TOKEN = '5c2777357a4aa5960799d01a02588c19fa90c3f498783376075dafda7d5d706a'
DING_SECRET = 'SEC058dab30c973edc0dd70b2a7e97eddfd33f20b45a5117b7c5d55c8f2d0dec474'
ding_robot = DingDingRobot(token=DING_TOKEN, secret=DING_SECRET)
# 4. 分批生成表格(避免钉钉字数限制,每批最多15行)
batch_size = 15
batches = [data[i:i + batch_size] for i in range(0, len(data), batch_size)]
for batch_idx, batch_data in enumerate(batches):
# 生成单批表格
mar_data = generate_markdown_table(batch_data)
# 分批标题(避免重复)
title = f"竞猜比赛结果(第{batch_idx + 1}批)" if len(batches) > 1 else "竞猜比赛结果"
# 构建消息体
msg_data = ding_robot.build_markdown_data(title=title, text=mar_data)
# 发送消息
success, message = ding_robot.send_message(msg_data)
print(f"{batch_idx + 1}批推送结果:{'成功' if success else '失败'},提示:{message}")
# 间隔1秒,避免触发钉钉频率限制
time.sleep(1)
if __name__ == '__main__':
main()