如何让两个Python Selenium线程分别读取credentials.txt不同行?
解决多线程读取不同凭证行的问题
问题说明
需要用Python Selenium创建2个线程,每个线程读取credentials.txt中的一行内容作为登录凭证:第一个线程读第一行,第二个线程读第二行。当前代码能启动两个线程,但两个线程始终读取同一行,无法按预期分别读取不同行。
原代码:
import csv from selenium import webdriver import time from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from threading import Thread line_count = 0 def login(): global line_count with open('credentials.txt') as csv_file: csv_reader = csv.reader(csv_file, delimiter=':') line_count = 0 for row in csv_reader: driver = webdriver.Chrome("C:\\Chromedriver.exe") driver.maximize_window() driver.get('https://twitter.com/i/flow/login') time.sleep(4) driver.find_element(By.NAME, "text").send_keys(row[0]) time.sleep(3) number_of_threads = 2 threads = [] for number in range(number_of_threads): t = Thread(target=login) t.start() threads.append(t) for t in threads: t.join()
问题根源
- 重复读取文件头部:每个线程都会重新打开
credentials.txt并从头开始遍历,所以两个线程都会先拿到文件的第一行内容。 - 全局变量失效:每个线程内部都重置了
line_count = 0,全局变量的同步逻辑完全失效,无法控制线程读取指定行。 - 循环逻辑错误:每个线程内的
for row in csv_reader会遍历所有行,导致单个线程会打开多个浏览器实例,不符合“一个线程处理一行”的需求。
修正方案
- 提前加载所有凭证:在启动线程前,先把
credentials.txt中的所有凭证读取到内存列表中,避免多个线程重复读取文件。 - 线程函数传参:让线程函数接收对应的凭证行作为参数,每个线程只处理分配给自己的那一行。
- 移除无效全局变量:不需要依赖全局变量控制读取位置,直接通过参数分配任务。
修正后的完整代码
import csv from selenium import webdriver import time from selenium.webdriver.common.by import By from threading import Thread def login(credential): # 每个线程只处理传入的单个凭证行 driver = webdriver.Chrome("C:\\Chromedriver.exe") driver.maximize_window() try: driver.get('https://twitter.com/i/flow/login') time.sleep(4) # 使用传入的凭证用户名 driver.find_element(By.NAME, "text").send_keys(credential[0]) time.sleep(3) # 这里可以继续添加后续登录步骤,比如点击下一步、输入密码等 finally: # 可以根据需求选择是否关闭浏览器 # driver.quit() pass if __name__ == "__main__": number_of_threads = 2 credentials = [] # 提前读取所有凭证到内存 with open('credentials.txt') as csv_file: csv_reader = csv.reader(csv_file, delimiter=':') credentials = list(csv_reader) # 确保凭证数量和线程数量匹配 if len(credentials) < number_of_threads: print(f"错误:凭证文件只有{len(credentials)}行,无法启动{number_of_threads}个线程") else: threads = [] # 为每个线程分配对应的凭证行 for i in range(number_of_threads): t = Thread(target=login, args=(credentials[i],)) t.start() threads.append(t) # 等待所有线程完成 for t in threads: t.join()
关键改动说明
- 提前加载凭证:在主线程中一次性读取所有凭证,避免多线程同时读取文件导致的资源竞争和重复读取问题。
- 线程传参:创建线程时通过
args参数把对应的凭证行传递给login函数,每个线程只处理自己的凭证。 - 异常处理:添加
try...finally块,确保浏览器资源能被正确管理(可以根据需求选择是否关闭浏览器)。 - 参数校验:增加了凭证数量和线程数量的匹配检查,避免出现索引越界错误。
内容的提问来源于stack exchange,提问作者Giovanni Di Renzo
相关产品推荐
相关产品推荐

