Compare commits

...

2 Commits

Author SHA1 Message Date
27942
79bf079548 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	bb_trade_log_20260228.txt
2026-03-02 10:56:08 +08:00
27942
aec9fc7830 haha 2026-03-02 10:55:39 +08:00
16 changed files with 1181 additions and 0 deletions

View File

@@ -339,6 +339,11 @@ class BBTrader:
except Exception as e:
logger.warning(f"写入日志失败: {e}")
def login(self):
self.page.ele('x://input[@placeholder="邮箱"]').input("ddrwode@gmail.com")
self.page.ele('x://input[@placeholder="密码"]').input("040828cjj")
self.page.ele('x://*[@id="__layout"]/div/div[2]/div/div[2]/div/div/div[2]/div[1]/div[2]/div/div[1]/div[2]/form/div[3]/div/button').click()
# ------------------------------------------------------------------
# 主循环(浏览器流程与四分之一代码一致)
# ------------------------------------------------------------------
@@ -377,6 +382,8 @@ class BBTrader:
logger.error("打开浏览器失败!")
return
# self.login()
self.page.get(self.cfg.TRADE_URL)
time.sleep(2)
# 点击市价模式

368
bb_trade_log_20260301.txt Normal file
View File

@@ -0,0 +1,368 @@
============================================================
时间: 2026-03-01 03:34:26
操作: 加仓空#1
价格: 1945.80
BB上轨: 1942.91 | 中轨: 1928.45 | 下轨: 1913.99
原因: 价格最高1945.80触及上轨1942.91BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 03:35:28
操作: 加仓空#2
价格: 1946.06
BB上轨: 1947.60 | 中轨: 1930.12 | 下轨: 1912.64
原因: 价格最高1948.81触及上轨1947.60BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 04:20:55
操作: 加仓空#3
价格: 1956.54
BB上轨: 1958.72 | 中轨: 1947.07 | 下轨: 1935.42
原因: 价格最高1963.78触及上轨1958.72BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 06:37:04
操作: 开空
价格: 1981.98
BB上轨: 1971.65 | 中轨: 1961.60 | 下轨: 1951.55
原因: 价格最高1982.00触及上轨1971.65BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 08:04:15
操作: 加仓空#1
价格: 1968.36
BB上轨: 1967.65 | 中轨: 1961.56 | 下轨: 1955.46
原因: 价格最高1968.37触及上轨1967.65BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 09:11:15
操作: 翻转: 平空→开多
价格: 1948.38
BB上轨: 1965.27 | 中轨: 1957.74 | 下轨: 1950.20
原因: 价格最低1948.07触及下轨1950.20BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 09:15:44
操作: 加仓多#1
价格: 1946.42
BB上轨: 1966.34 | 中轨: 1956.43 | 下轨: 1946.53
原因: 价格最低1946.20触及下轨1946.53BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 09:37:21
操作: 翻转: 平多→开空
价格: 1966.51
BB上轨: 1967.60 | 中轨: 1955.23 | 下轨: 1942.85
原因: 价格最高1967.64触及上轨1967.60BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 09:47:41
操作: 加仓空#1
价格: 1974.91
BB上轨: 1973.88 | 中轨: 1956.84 | 下轨: 1939.80
原因: 价格最高1974.91触及上轨1973.88BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 09:50:10
操作: 加仓空#2
价格: 1990.01
BB上轨: 1988.73 | 中轨: 1959.52 | 下轨: 1930.30
原因: 价格最高1991.56触及上轨1988.73BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 09:59:41
操作: 开空
价格: 2009.09
BB上轨: 2008.95 | 中轨: 1964.55 | 下轨: 1920.15
原因: 价格最高2009.20触及上轨2008.95BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 10:02:15
操作: 加仓空#1
价格: 2023.05
BB上轨: 2025.72 | 中轨: 1970.39 | 下轨: 1915.07
原因: 价格最高2026.00触及上轨2025.72BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 11:22:14
操作: 开多
价格: 2028.59
BB上轨: 2042.05 | 中轨: 2035.46 | 下轨: 2028.87
原因: 价格最低2028.58触及下轨2028.87BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 11:54:08
操作: 加仓多#1
价格: 2023.39
BB上轨: 2039.59 | 中轨: 2032.27 | 下轨: 2024.96
原因: 价格最低2021.86触及下轨2024.96BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 11:55:14
操作: 加仓多#2
价格: 2020.39
BB上轨: 2042.34 | 中轨: 2030.59 | 下轨: 2018.84
原因: 价格最低2018.50触及下轨2018.84BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 12:15:00
操作: 加仓多#3
价格: 2012.23
BB上轨: 2039.99 | 中轨: 2026.95 | 下轨: 2013.91
原因: 价格最低2008.07触及下轨2013.91BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 13:20:34
操作: 翻转: 平多→开空
价格: 2017.26
BB上轨: 2017.21 | 中轨: 2014.22 | 下轨: 2011.24
原因: 价格最高2017.47触及上轨2017.21BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 13:25:07
操作: 加仓空#1
价格: 2021.89
BB上轨: 2021.00 | 中轨: 2015.09 | 下轨: 2009.17
原因: 价格最高2021.58触及上轨2021.00BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 13:55:06
操作: 翻转: 平空→开多
价格: 2009.30
BB上轨: 2023.23 | 中轨: 2016.18 | 下轨: 2009.13
原因: 价格最低2008.73触及下轨2009.13BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 14:04:49
操作: 加仓多#1
价格: 2005.00
BB上轨: 2024.71 | 中轨: 2015.13 | 下轨: 2005.56
原因: 价格最低2005.00触及下轨2005.56BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 14:05:27
操作: 加仓多#2
价格: 2001.68
BB上轨: 2026.45 | 中轨: 2014.43 | 下轨: 2002.41
原因: 价格最低2001.68触及下轨2002.41BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 14:10:46
操作: 加仓多#3
价格: 1993.93
BB上轨: 2029.77 | 中轨: 2012.76 | 下轨: 1995.76
原因: 价格最低1993.62触及下轨1995.76BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 15:12:06
操作: 翻转: 平多→开空
价格: 2003.74
BB上轨: 2003.48 | 中轨: 1996.50 | 下轨: 1989.52
原因: 价格最高2003.74触及上轨2003.48BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 15:22:02
操作: 加仓空#1
价格: 2004.51
BB上轨: 2004.32 | 中轨: 1996.69 | 下轨: 1989.06
原因: 价格最高2004.51触及上轨2004.32BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 15:39:37
操作: 加仓空#2
价格: 2006.49
BB上轨: 2005.89 | 中轨: 1998.49 | 下轨: 1991.09
原因: 价格最高2007.16触及上轨2005.89BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 15:40:18
操作: 加仓空#3
价格: 2005.95
BB上轨: 2008.50 | 中轨: 1999.85 | 下轨: 1991.20
原因: 价格最高2008.89触及上轨2008.50BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 16:47:20
操作: 翻转: 平空→开多
价格: 1997.54
BB上轨: 2011.42 | 中轨: 2004.66 | 下轨: 1997.89
原因: 价格最低1997.54触及下轨1997.89BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 16:50:39
操作: 加仓多#1
价格: 1994.11
BB上轨: 2012.88 | 中轨: 2003.62 | 下轨: 1994.36
原因: 价格最低1994.00触及下轨1994.36BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 16:55:10
操作: 加仓多#2
价格: 1984.53
BB上轨: 2019.59 | 中轨: 2002.06 | 下轨: 1984.53
原因: 价格最低1984.04触及下轨1984.53BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 17:02:18
操作: 加仓多#3
价格: 1977.78
BB上轨: 2021.30 | 中轨: 2000.09 | 下轨: 1978.87
原因: 价格最低1977.34触及下轨1978.87BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 18:26:31
操作: 翻转: 平多→开空
价格: 1981.80
BB上轨: 1982.79 | 中轨: 1979.44 | 下轨: 1976.08
原因: 价格最高1982.80触及上轨1982.79BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 18:30:23
操作: 加仓空#1
价格: 1985.00
BB上轨: 1984.64 | 中轨: 1979.89 | 下轨: 1975.13
原因: 价格最高1985.00触及上轨1984.64BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 18:35:09
操作: 加仓空#2
价格: 1986.68
BB上轨: 1986.58 | 中轨: 1980.49 | 下轨: 1974.40
原因: 价格最高1986.68触及上轨1986.58BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 19:16:32
操作: 加仓空#3
价格: 1987.27
BB上轨: 1987.94 | 中轨: 1983.79 | 下轨: 1979.63
原因: 价格最高1987.96触及上轨1987.94BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 20:28:43
操作: 翻转: 平空→开多
价格: 1979.84
BB上轨: 1987.42 | 中轨: 1983.66 | 下轨: 1979.90
原因: 价格最低1979.64触及下轨1979.90BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 20:34:05
操作: 加仓多#1
价格: 1978.24
BB上轨: 1987.88 | 中轨: 1983.22 | 下轨: 1978.55
原因: 价格最低1978.24触及下轨1978.55BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 21:20:40
操作: 加仓多#2
价格: 1973.00
BB上轨: 1982.99 | 中轨: 1978.04 | 下轨: 1973.10
原因: 价格最低1973.00触及下轨1973.10BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 21:51:21
操作: 翻转: 平多→开空
价格: 1981.17
BB上轨: 1980.40 | 中轨: 1976.08 | 下轨: 1971.77
原因: 价格最高1981.82触及上轨1980.40BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 21:55:09
操作: 开空
价格: 2019.50
BB上轨: 2011.12 | 中轨: 1980.16 | 下轨: 1949.21
原因: 价格最高2019.50触及上轨2011.12BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 22:42:31
操作: 翻转: 平空→开多
价格: 1998.46
BB上轨: 2021.45 | 中轨: 2010.61 | 下轨: 1999.77
原因: 价格最低1997.98触及下轨1999.77BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 22:45:18
操作: 加仓多#1
价格: 1995.73
BB上轨: 2021.76 | 中轨: 2008.71 | 下轨: 1995.66
原因: 价格最低1995.55触及下轨1995.66BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 23:17:24
操作: 翻转: 平多→开空
价格: 2011.33
BB上轨: 2011.41 | 中轨: 2003.47 | 下轨: 1995.52
原因: 价格最高2011.70触及上轨2011.41BB(10,2.5)
============================================================
============================================================
时间: 2026-03-01 23:20:33
操作: 加仓空#1
价格: 2013.00
BB上轨: 2012.52 | 中轨: 2003.72 | 下轨: 1994.92
原因: 价格最高2013.00触及上轨2012.52BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-01 23:28:46
操作: 加仓空#2
价格: 2012.26
BB上轨: 2012.18 | 中轨: 2003.62 | 下轨: 1995.05
原因: 价格最高2012.30触及上轨2012.18BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-01 23:34:42
操作: 加仓空#3
价格: 2012.90
BB上轨: 2013.39 | 中轨: 2003.97 | 下轨: 1994.56
原因: 价格最高2013.42触及上轨2013.39BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-01 23:57:04
操作: 翻转: 平空→开多
价格: 2000.60
BB上轨: 2017.24 | 中轨: 2008.93 | 下轨: 2000.62
原因: 价格最低2000.38触及下轨2000.62BB(10,2.5)
============================================================

160
bb_trade_log_20260302.txt Normal file
View File

@@ -0,0 +1,160 @@
============================================================
时间: 2026-03-02 00:00:12
操作: 加仓多#1
价格: 1993.03
BB上轨: 2022.56 | 中轨: 2007.82 | 下轨: 1993.08
原因: 价格最低1992.31触及下轨1993.08BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-02 00:47:35
操作: 加仓多#2
价格: 1991.52
BB上轨: 2009.23 | 中轨: 2000.42 | 下轨: 1991.62
原因: 价格最低1991.22触及下轨1991.62BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-02 00:50:07
操作: 加仓多#3
价格: 1972.92
BB上轨: 2020.78 | 中轨: 1998.46 | 下轨: 1976.14
原因: 价格最低1972.33触及下轨1976.14BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-02 02:54:45
操作: 翻转: 平空→开多
价格: 1975.78
BB上轨: 1987.69 | 中轨: 1981.61 | 下轨: 1975.53
原因: 价格最低1974.35触及下轨1975.53BB(10,2.5)
============================================================
============================================================
时间: 2026-03-02 02:55:32
操作: 加仓多#1
价格: 1972.67
BB上轨: 1988.35 | 中轨: 1980.89 | 下轨: 1973.42
原因: 价格最低1972.66触及下轨1973.42BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-02 03:01:38
操作: 加仓多#2
价格: 1973.37
BB上轨: 1985.83 | 中轨: 1979.58 | 下轨: 1973.32
原因: 价格最低1972.87触及下轨1973.32BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-02 03:06:27
操作: 加仓多#3
价格: 1969.61
BB上轨: 1986.78 | 中轨: 1978.35 | 下轨: 1969.93
原因: 价格最低1968.00触及下轨1969.93BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-02 04:10:24
操作: 开多
价格: 1938.14
BB上轨: 1968.16 | 中轨: 1954.01 | 下轨: 1939.86
原因: 价格最低1932.00触及下轨1939.86BB(10,2.5)
============================================================
============================================================
时间: 2026-03-02 04:15:20
操作: 加仓多#1
价格: 1931.04
BB上轨: 1971.27 | 中轨: 1951.22 | 下轨: 1931.16
原因: 价格最低1931.04触及下轨1931.16BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-02 05:21:09
操作: 翻转: 平多→开空
价格: 1925.01
BB上轨: 1925.19 | 中轨: 1914.61 | 下轨: 1904.03
原因: 价格最高1926.00触及上轨1925.19BB(10,2.5)
============================================================
============================================================
时间: 2026-03-02 06:03:53
操作: 加仓空#1
价格: 1930.73
BB上轨: 1930.55 | 中轨: 1925.10 | 下轨: 1919.65
原因: 价格最高1930.73触及上轨1930.55BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-02 06:13:08
操作: 加仓空#2
价格: 1933.10
BB上轨: 1930.98 | 中轨: 1926.37 | 下轨: 1921.75
原因: 价格最高1933.10触及上轨1930.98BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-02 06:15:10
操作: 开空
价格: 1944.64
BB上轨: 1942.77 | 中轨: 1928.24 | 下轨: 1913.72
原因: 价格最高1945.94触及上轨1942.77BB(10,2.5)
============================================================
============================================================
时间: 2026-03-02 08:07:31
操作: 加仓空#1
价格: 1943.79
BB上轨: 1945.86 | 中轨: 1937.82 | 下轨: 1929.77
原因: 价格最高1945.97触及上轨1945.86BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-02 08:10:09
操作: 加仓空#2
价格: 1950.40
BB上轨: 1948.66 | 中轨: 1938.79 | 下轨: 1928.92
原因: 价格最高1950.40触及上轨1948.66BB(10,2.5) (加仓#2/3)
============================================================
============================================================
时间: 2026-03-02 08:32:48
操作: 加仓空#3
价格: 1950.23
BB上轨: 1950.72 | 中轨: 1942.27 | 下轨: 1933.83
原因: 价格最高1950.89触及上轨1950.72BB(10,2.5) (加仓#3/3)
============================================================
============================================================
时间: 2026-03-02 09:10:45
操作: 开空
价格: 1980.63
BB上轨: 1979.30 | 中轨: 1956.47 | 下轨: 1933.64
原因: 价格最高1982.52触及上轨1979.30BB(10,2.5)
============================================================
============================================================
时间: 2026-03-02 10:06:29
操作: 翻转: 平空→开多
价格: 1956.56
BB上轨: 1977.03 | 中轨: 1966.90 | 下轨: 1956.77
原因: 价格最低1956.32触及下轨1956.77BB(10,2.5)
============================================================
============================================================
时间: 2026-03-02 10:10:10
操作: 加仓多#1
价格: 1948.99
BB上轨: 1978.42 | 中轨: 1964.20 | 下轨: 1949.99
原因: 价格最低1948.98触及下轨1949.99BB(10,2.5) (加仓#1/3)
============================================================
============================================================
时间: 2026-03-02 10:19:45
操作: 加仓多#2
价格: 1941.70
BB上轨: 1981.96 | 中轨: 1961.75 | 下轨: 1941.53
原因: 价格最低1941.34触及下轨1941.53BB(10,2.5) (加仓#2/3)
============================================================

113
captcha_clip.py Normal file
View File

@@ -0,0 +1,113 @@
"""
用 CLIP 做图块相似度匹配,在大图中找模板图标位置
原理:把大图切成滑动窗口小块,用 CLIP 计算每块和模板的视觉相似度,取最高分的块
"""
import cv2
import numpy as np
from PIL import Image
import torch
from transformers import CLIPProcessor, CLIPModel
from pathlib import Path
BASE = Path(__file__).parent / "images"
MODEL_NAME = "openai/clip-vit-base-patch32" # 约600MB小模型
def load_clip():
print("加载 CLIP 模型约600MB首次自动下载...")
model = CLIPModel.from_pretrained(MODEL_NAME).to("cuda")
processor = CLIPProcessor.from_pretrained(MODEL_NAME)
print("CLIP 加载完成")
return model, processor
def find_by_clip(model, processor, main_img: np.ndarray, template_img: np.ndarray,
step=10, win_sizes=None):
"""
滑动窗口 + CLIP 相似度,找模板在大图中的最佳位置
"""
if win_sizes is None:
th, tw = template_img.shape[:2]
# 尝试原始尺寸及上下浮动
win_sizes = [(int(tw * s), int(th * s)) for s in [0.8, 0.9, 1.0, 1.1, 1.2]]
# 预处理模板
tmpl_pil = Image.fromarray(cv2.cvtColor(template_img, cv2.COLOR_BGR2RGB))
tmpl_inputs = processor(images=tmpl_pil, return_tensors="pt").to("cuda")
with torch.no_grad():
tmpl_out = model.vision_model(**tmpl_inputs)
tmpl_feat = model.visual_projection(tmpl_out.pooler_output).float()
tmpl_feat = tmpl_feat / tmpl_feat.norm(dim=-1, keepdim=True)
mh, mw = main_img.shape[:2]
best_score = -1
best_box = None
for (ww, wh) in win_sizes:
if ww > mw or wh > mh:
continue
for y in range(0, mh - wh + 1, step):
for x in range(0, mw - ww + 1, step):
crop = main_img[y:y+wh, x:x+ww]
crop_pil = Image.fromarray(cv2.cvtColor(crop, cv2.COLOR_BGR2RGB))
crop_inputs = processor(images=crop_pil, return_tensors="pt").to("cuda")
with torch.no_grad():
crop_out = model.vision_model(**crop_inputs)
crop_feat = model.visual_projection(crop_out.pooler_output).float()
crop_feat = crop_feat / crop_feat.norm(dim=-1, keepdim=True)
score = (tmpl_feat * crop_feat).sum().item()
if score > best_score:
best_score = score
best_box = (x, y, ww, wh)
return best_box, best_score
def main():
main_img = cv2.imread(str(BASE / "1.jpg"))
templates = {
"2.png": cv2.imread(str(BASE / "2.png")),
"3.png": cv2.imread(str(BASE / "3.png")),
"4.png": cv2.imread(str(BASE / "4.png")),
}
# 模板是 BGRA转 BGR
for name in templates:
img = cv2.imread(str(BASE / name), cv2.IMREAD_UNCHANGED)
if img.shape[2] == 4:
# alpha 通道合成白底
alpha = img[:, :, 3:4] / 255.0
rgb = img[:, :, :3].astype(float)
white = np.ones_like(rgb) * 255
merged = (rgb * alpha + white * (1 - alpha)).astype(np.uint8)
templates[name] = merged
else:
templates[name] = img
model, processor = load_clip()
vis = main_img.copy()
colors = {"2.png": (0, 0, 255), "3.png": (0, 255, 0), "4.png": (255, 0, 0)}
print()
for name, tmpl in templates.items():
print(f"正在匹配 {name} ...")
box, score = find_by_clip(model, processor, main_img, tmpl, step=8)
if box:
x, y, w, h = box
cx, cy = x + w // 2, y + h // 2
color = colors[name]
cv2.rectangle(vis, (x, y), (x+w, y+h), color, 2)
cv2.circle(vis, (cx, cy), 5, color, -1)
cv2.putText(vis, name, (x, y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)
print(f" {name}: 中心点 ({cx}, {cy}) 相似度={score:.4f}")
else:
print(f" {name}: 未找到")
out = BASE / "result_clip.jpg"
cv2.imwrite(str(out), vis)
print(f"\n结果保存到: {out}")
if __name__ == "__main__":
main()

131
captcha_vl.py Normal file
View File

@@ -0,0 +1,131 @@
"""
用 Qwen2-VL 本地模型识别验证码图片位置
首次运行会自动下载模型(约 4GB
"""
import base64
from pathlib import Path
from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
from qwen_vl_utils import process_vision_info
import torch
MODEL_NAME = "Qwen/Qwen2-VL-7B-Instruct"
BASE = Path(__file__).parent / "images"
def img_to_base64(path):
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()
def load_model():
print("加载模型中首次运行会下载约15GB...")
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
)
model = Qwen2VLForConditionalGeneration.from_pretrained(
MODEL_NAME,
quantization_config=bnb_config,
device_map="cuda",
)
processor = AutoProcessor.from_pretrained(MODEL_NAME)
print("模型加载完成")
return model, processor
def ask_one(model, processor, main_img_path, template_path):
"""让模型找出单个模板图在主图中的位置,返回原始回答"""
messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": (
"下面是一张背景大图300x200像素"
"以及一个需要在大图中找到的小图标轮廓。\n"
"大图:"
)
},
{"type": "image", "image": str(main_img_path)},
{
"type": "text",
"text": "\n小图标轮廓(这个图标出现在大图中某个物体上):"
},
{"type": "image", "image": str(template_path)},
{
"type": "text",
"text": (
"\n请仔细观察小图标的形状,在大图中找到形状最相似的物体,"
"给出该物体中心点的像素坐标。"
"坐标原点在左上角x向右y向下。"
"只需回答坐标,格式:(x, y)"
)
}
]
}
]
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(
text=[text],
images=image_inputs,
videos=video_inputs,
padding=True,
return_tensors="pt",
).to("cuda")
with torch.no_grad():
generated_ids = model.generate(**inputs, max_new_tokens=50)
generated_ids_trimmed = [
out_ids[len(in_ids):] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
]
output = processor.batch_decode(
generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
)
return output[0].strip()
def main():
main_img = BASE / "1.jpg"
templates = [BASE / "2.png", BASE / "3.png", BASE / "4.png"]
model, processor = load_model()
import re
import cv2
img = cv2.imread(str(main_img))
colors = {"2.png": (0, 0, 255), "3.png": (0, 255, 0), "4.png": (255, 0, 0)}
results = {}
for tmpl_path in templates:
name = tmpl_path.name
print(f"\n正在识别 {name} ...")
answer = ask_one(model, processor, main_img, tmpl_path)
print(f"{name} 模型回答: {answer}")
match = re.search(r"\((\d+)[,\s]+(\d+)\)", answer)
if match:
x, y = int(match.group(1)), int(match.group(2))
results[name] = (x, y)
color = colors[name]
cv2.circle(img, (x, y), 8, color, -1)
cv2.circle(img, (x, y), 12, color, 2)
cv2.putText(img, name, (x + 14, y + 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)
else:
print(f"{name}: 未能解析坐标,原始回答: {answer}")
print("\n=== 点击坐标汇总 ===")
for name, (x, y) in results.items():
print(f"{name}: ({x}, {y})")
out = BASE / "result_vl.jpg"
cv2.imwrite(str(out), img)
print(f"\n可视化结果保存到: {out}")
if __name__ == "__main__":
main()

1
credentials.json Normal file
View File

@@ -0,0 +1 @@
{"installed":{"client_id":"823839778551-mgovppr13aoil1r69upj7uiv84ej0sih.apps.googleusercontent.com","project_id":"gen-lang-client-0535910705","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost"]}}

127
find_captcha.py Normal file
View File

@@ -0,0 +1,127 @@
"""
验证码图片匹配脚本
在 1.jpg 中找到 2.png、3.png、4.png 的位置
"""
import cv2
import numpy as np
import os
def find_template_in_image(main_img_path, template_path, threshold=0.5):
"""
在主图中查找模板图片的位置(原始尺寸 + 多尺度)
支持 PNG alpha 通道作为模板轮廓
返回置信度最高的匹配结果
"""
main_img = cv2.imread(main_img_path)
template = cv2.imread(template_path, cv2.IMREAD_UNCHANGED)
if main_img is None:
print(f"无法读取主图: {main_img_path}")
return []
if template is None:
print(f"无法读取模板: {template_path}")
return []
h, w = template.shape[:2]
main_gray = cv2.cvtColor(main_img, cv2.COLOR_BGR2GRAY)
# 如果模板有 alpha 通道且 RGB 全黑,用 alpha 通道作为灰度图
if template.shape[2] == 4:
alpha = template[:, :, 3]
rgb_sum = template[:, :, :3].sum()
if rgb_sum == 0:
tmpl_gray = alpha # 用 alpha 通道
else:
tmpl_gray = cv2.cvtColor(template[:, :, :3], cv2.COLOR_BGR2GRAY)
else:
tmpl_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
best = None
# 先尝试原始尺寸
scales = [1.0] + list(np.linspace(0.6, 1.4, 17))
for scale in scales:
rw, rh = int(w * scale), int(h * scale)
if rh < 5 or rw < 5:
continue
if rh > main_gray.shape[0] or rw > main_gray.shape[1]:
continue
resized_tmpl = cv2.resize(tmpl_gray, (rw, rh))
res = cv2.matchTemplate(main_gray, resized_tmpl, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(res)
if best is None or max_val > best["confidence"]:
best = {
"x": max_loc[0],
"y": max_loc[1],
"w": rw,
"h": rh,
"confidence": max_val,
"scale": scale,
"center_x": max_loc[0] + rw // 2,
"center_y": max_loc[1] + rh // 2,
}
if best is None or best["confidence"] < threshold:
return []
return [best]
def main():
base_dir = os.path.join(os.path.dirname(__file__), "images")
main_img_path = os.path.join(base_dir, "1.jpg")
templates = ["2.png", "3.png", "4.png"]
print(f"主图: {main_img_path}\n")
all_results = {}
for tmpl_name in templates:
tmpl_path = os.path.join(base_dir, tmpl_name)
matches = find_template_in_image(main_img_path, tmpl_path, threshold=0.5)
all_results[tmpl_name] = matches
if matches:
m = matches[0]
print(f"[{tmpl_name}] 找到匹配:")
print(f" 位置: ({m['x']}, {m['y']})")
print(f" 中心点: ({m['center_x']}, {m['center_y']})")
print(f" 尺寸: {m['w']}x{m['h']}")
print(f" 置信度: {m['confidence']:.4f}")
print(f" 缩放比例: {m['scale']:.2f}")
else:
print(f"[{tmpl_name}] 未找到匹配(置信度不足)")
print()
# 可视化结果,保存标注图
main_img = cv2.imread(main_img_path)
colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0)] # 红、绿、蓝
for i, tmpl_name in enumerate(templates):
matches = all_results.get(tmpl_name, [])
for m in matches:
x, y, w, h = m["x"], m["y"], m["w"], m["h"]
color = colors[i % len(colors)]
cv2.rectangle(main_img, (x, y), (x + w, y + h), color, 2)
cv2.putText(main_img, tmpl_name, (x, y - 5),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
# 画中心点
cx, cy = m["center_x"], m["center_y"]
cv2.circle(main_img, (cx, cy), 5, color, -1)
output_path = os.path.join(base_dir, "result.jpg")
cv2.imwrite(output_path, main_img)
print(f"标注结果已保存到: {output_path}")
# 打印点击坐标汇总(用于自动化点击)
print("\n=== 点击坐标汇总 ===")
for tmpl_name in templates:
matches = all_results.get(tmpl_name, [])
if matches:
m = matches[0]
print(f"{tmpl_name}: 点击 ({m['center_x']}, {m['center_y']})")
else:
print(f"{tmpl_name}: 未找到")
if __name__ == "__main__":
main()

208
gmail_reader.py Normal file
View File

@@ -0,0 +1,208 @@
"""
Gmail API 邮件读取工具
使用前准备:
1. 访问 https://console.cloud.google.com/ 创建项目
2. 启用 Gmail API
3. 创建 OAuth 2.0 凭据(桌面应用类型),下载 credentials.json 放到本目录
4. 首次运行会弹出浏览器授权,授权后自动生成 token.json
"""
import os
import base64
import json
from datetime import datetime
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from email.utils import parsedate_to_datetime
# 只读权限
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
# 凭据文件路径(和脚本同目录)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CREDENTIALS_FILE = os.path.join(BASE_DIR, 'credentials.json')
TOKEN_FILE = os.path.join(BASE_DIR, 'token.json')
def get_service():
"""获取 Gmail API 服务实例"""
creds = None
# 尝试加载已有 token
if os.path.exists(TOKEN_FILE):
creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
# token 无效或过期,重新授权
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
if not os.path.exists(CREDENTIALS_FILE):
print(f"❌ 找不到 {CREDENTIALS_FILE}")
print("请从 Google Cloud Console 下载 OAuth 凭据文件,命名为 credentials.json 放到本目录")
return None
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_FILE, SCOPES)
creds = flow.run_local_server(port=0)
# 保存 token 供下次使用
with open(TOKEN_FILE, 'w') as f:
f.write(creds.to_json())
return build('gmail', 'v1', credentials=creds)
def decode_body(payload):
"""递归解析邮件正文(优先纯文本)"""
# 直接有 body data
if 'body' in payload and payload['body'].get('data'):
return base64.urlsafe_b64decode(payload['body']['data']).decode('utf-8', errors='ignore')
# 多部分邮件,递归查找
if 'parts' in payload:
# 优先找 text/plain
for part in payload['parts']:
if part.get('mimeType') == 'text/plain':
data = part['body'].get('data', '')
if data:
return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
# 没有纯文本,找 text/html
for part in payload['parts']:
if part.get('mimeType') == 'text/html':
data = part['body'].get('data', '')
if data:
return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
# 递归子部分
for part in payload['parts']:
result = decode_body(part)
if result:
return result
return None
def get_header(headers, name):
"""从 headers 列表中取指定字段"""
for h in headers:
if h['name'].lower() == name.lower():
return h['value']
return ''
def list_emails(service, query='', label_ids=None, max_results=10):
"""
列出邮件
:param query: Gmail 搜索语法,如 'from:xxx@gmail.com' 'subject:报告' 'is:unread'
:param label_ids: 标签过滤,如 ['INBOX'], ['UNREAD']
:param max_results: 最多返回条数
"""
params = {'userId': 'me', 'maxResults': max_results}
if query:
params['q'] = query
if label_ids:
params['labelIds'] = label_ids
results = service.users().messages().list(**params).execute()
return results.get('messages', [])
def read_email(service, msg_id):
"""读取单封邮件详情"""
msg = service.users().messages().get(userId='me', id=msg_id, format='full').execute()
headers = msg['payload']['headers']
subject = get_header(headers, 'Subject') or '(无主题)'
sender = get_header(headers, 'From')
to = get_header(headers, 'To')
date_str = get_header(headers, 'Date')
body = decode_body(msg['payload']) or '(无正文)'
# 解析日期
try:
date = parsedate_to_datetime(date_str)
date_str = date.strftime('%Y-%m-%d %H:%M:%S')
except Exception:
pass
return {
'id': msg_id,
'subject': subject,
'from': sender,
'to': to,
'date': date_str,
'body': body,
'labels': msg.get('labelIds', []),
'snippet': msg.get('snippet', ''),
}
def get_attachments(service, msg_id, save_dir=None):
"""下载邮件附件"""
msg = service.users().messages().get(userId='me', id=msg_id, format='full').execute()
attachments = []
if save_dir is None:
save_dir = os.path.join(BASE_DIR, 'attachments')
def _find_attachments(payload):
if 'parts' in payload:
for part in payload['parts']:
filename = part.get('filename', '')
if filename and part['body'].get('attachmentId'):
att = service.users().messages().attachments().get(
userId='me', messageId=msg_id, id=part['body']['attachmentId']
).execute()
data = base64.urlsafe_b64decode(att['data'])
os.makedirs(save_dir, exist_ok=True)
filepath = os.path.join(save_dir, filename)
with open(filepath, 'wb') as f:
f.write(data)
attachments.append({'filename': filename, 'path': filepath, 'size': len(data)})
print(f" 📎 已保存附件: {filename} ({len(data)} bytes)")
# 递归
_find_attachments(part)
_find_attachments(msg['payload'])
return attachments
# ============ 使用示例 ============
if __name__ == '__main__':
service = get_service()
if not service:
exit(1)
print("=" * 60)
print("📬 Gmail 邮件读取")
print("=" * 60)
# --- 示例1: 读取收件箱最近 5 封邮件 ---
print("\n📥 收件箱最近 5 封邮件:\n")
messages = list_emails(service, label_ids=['INBOX'], max_results=5)
for m in messages:
email_data = read_email(service, m['id'])
print(f"📧 主题: {email_data['subject']}")
print(f" 发件人: {email_data['from']}")
print(f" 日期: {email_data['date']}")
print(f" 摘要: {email_data['snippet'][:80]}...")
print()
# --- 示例2: 搜索特定邮件(取消注释使用)---
# messages = list_emails(service, query='subject:报告 is:unread', max_results=5)
# --- 示例3: 读取完整正文 ---
# if messages:
# email_data = read_email(service, messages[0]['id'])
# print(f"\n完整正文:\n{email_data['body']}")
# --- 示例4: 下载附件 ---
# if messages:
# get_attachments(service, messages[0]['id'])

BIN
images/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
images/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
images/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
images/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
images/result_clip.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
images/result_vl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

65
match_alpha.py Normal file
View File

@@ -0,0 +1,65 @@
import cv2
import numpy as np
base = 'c:/Users/27942/Desktop/codes/codex_jxs_code/images/'
main_img = cv2.imread(base + '1.jpg')
main_gray = cv2.cvtColor(main_img, cv2.COLOR_BGR2GRAY)
def match_template_alpha(main_gray, alpha, name):
h, w = alpha.shape[:2]
best = None
# 策略1: 直接用alpha通道匹配灰度图
# 策略2: 用alpha做mask只比较非透明区域
# 策略3: 对alpha二值化后匹配
_, alpha_bin = cv2.threshold(alpha, 10, 255, cv2.THRESH_BINARY)
scales = [1.0] + list(np.linspace(0.65, 1.35, 29))
for scale in scales:
rw, rh = int(w * scale), int(h * scale)
if rh < 10 or rw < 10:
continue
if rh > main_gray.shape[0] or rw > main_gray.shape[1]:
continue
resized_alpha = cv2.resize(alpha, (rw, rh))
resized_bin = cv2.resize(alpha_bin, (rw, rh))
_, resized_mask = cv2.threshold(resized_bin, 10, 255, cv2.THRESH_BINARY)
# 用mask匹配只看非透明区域
res = cv2.matchTemplate(main_gray, resized_alpha, cv2.TM_CCOEFF_NORMED, mask=resized_mask)
_, max_val, _, max_loc = cv2.minMaxLoc(res)
if best is None or max_val > best['conf']:
best = {
'x': max_loc[0], 'y': max_loc[1],
'w': rw, 'h': rh,
'conf': max_val, 'scale': scale,
'cx': max_loc[0] + rw // 2,
'cy': max_loc[1] + rh // 2,
}
return best
results = {}
for name in ['2.png', '3.png', '4.png']:
template = cv2.imread(base + name, cv2.IMREAD_UNCHANGED)
alpha = template[:, :, 3]
best = match_template_alpha(main_gray, alpha, name)
results[name] = best
x, y, cx, cy = best['x'], best['y'], best['cx'], best['cy']
conf, scale = best['conf'], best['scale']
print(name + ': pos=(' + str(x) + ',' + str(y) + ') center=(' + str(cx) + ',' + str(cy) + ') conf=' + str(round(conf, 4)) + ' scale=' + str(round(scale, 2)))
# 可视化
colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0)]
vis = main_img.copy()
for i, name in enumerate(['2.png', '3.png', '4.png']):
m = results[name]
cv2.rectangle(vis, (m['x'], m['y']), (m['x'] + m['w'], m['y'] + m['h']), colors[i], 2)
cv2.putText(vis, name, (m['x'], m['y'] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[i], 1)
cv2.circle(vis, (m['cx'], m['cy']), 5, colors[i], -1)
cv2.imwrite(base + 'result.jpg', vis)
print('result saved to images/result.jpg')

1
token.json Normal file
View File

@@ -0,0 +1 @@
{"token": "ya29.a0ATkoCc7EYaXMumpShCwmfiq5pqSbgMB_XkUuWWUFnYRs8fvfPt6xYaU3r8rrdiFWHpQ_07R2FN_ML4X-4Q9eoHp5Dj6R0xgL1A9xFONvaJhlEP_ndce3Uht6LpeIUhfoGw2fHU9ZlvKcVNyCfcGsTqsR8YXWoe49MmU3k-DiHQgIDrxZ0c7Kyfb0FltZ9bUwXJg8ILIaCgYKAYUSARMSFQHGX2MiD7gOuz1kuvvNQABqx39YNw0206", "refresh_token": "1//0gVVN8c-x-T1MCgYIARAAGBASNwF-L9IrNPuDnHu-3vZoJvPChjsyjrUwtlSX7qmY_xnwFUr0FPf-t7Tm53f3vSo4OZOaJWSqA0s", "token_uri": "https://oauth2.googleapis.com/token", "client_id": "823839778551-mgovppr13aoil1r69upj7uiv84ej0sih.apps.googleusercontent.com", "client_secret": "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", "scopes": ["https://www.googleapis.com/auth/gmail.readonly"], "universe_domain": "googleapis.com", "account": "", "expiry": "2026-02-28T19:35:00Z"}