我有一个下载个股日线数据的python程序,单线程运行没问题但是耗时太久要40分钟。后来我改为多线程,虽然速度大幅提高,但偶然会出现假死的现象,就是程序运行到某个进度就卡住完全不动了,这个现象有时候出现有时候则正常。
我查阅资料后认为有如下3种可能性:
1、出现了死锁的问题
2、请求网络数据的时候出了问题,迟迟没有获取返回值
3、程序写入时出错,或者是程序本身有缺陷
import os
import time
import datetime
import requests
import threading
import pandas as pd
from concurrent.futures import ThreadPoolExecutor,as_completed
class UpdateStockData:
lock = threading.Lock() # 全局定义一个 Lock()
def __init__(self,stock_path,user_agent,threading_num):
self.stock_path = stock_path
self.user_agent = user_agent
self.threading_num = threading_num
self.start_date = '20220701' # start_date用于构建网易url
self.end_date = ''.join(str(datetime.date.today()).split('-')) # 一般就是今天 20220921
self.stock_code_list = []
self.empty_list = []
self.total_stock_num = 0
self.finished_num = 0
# 获取所有的股票数据 这里面已验证完全没问题,不用修改。
def getStockDataFromSina(self):
page = 1
df = pd.DataFrame()
headers = {'Referer': 'http://finance.sina.com.cn',
'User-Agent': self.user_agent}
while True:
url = 'http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page=' \
+ str(page) + '&num=80&sort=symbol&asc=1&node=hs_a&symbol=&_s_r_a=sort'
for i in range(10): # 向新浪请求数据的次数,限制在10次
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200:
content = response.json()
break
elif i < 9:
print("链接失败,接收到如下信息\n", response)
time.sleep(5)
elif i == 9:
exit(f'连续10次向新浪请求第{page}数据失败,程序已终止')
if not content:
print("\n新浪股票信息已获取完毕。")
break
print('\r' + f"已读取新浪第{page}页数据", end='', flush=True)
df = df.append(pd.DataFrame(content, dtype='float'), ignore_index=True)
page += 1
time.sleep(0.6)
self.stock_code_list = list(df.symbol)
self.total_stock_num = len(self.stock_code_list)
return
# ==== 下载个股数据_单进程
def updateStock_pool_per(self,code_url):
stock_code = code_url[0]
download_url = code_url[1]
# 读取网易数据,期间可能会出错,以下为异常处理
sleep_time = 1 # 出错后停顿的时间
try_count = 0
while True:
try:
df = pd.read_csv(download_url, encoding='gbk') # 直接将网易上的文件数据读取下来
except Exception as e:
try_count += 1
print(f'\n在下载{stock_code}时报错,错误信息为:\n{e}\n已尝试第{try_count}次,暂停{sleep_time}秒后再尝试')
time.sleep(sleep_time)
if try_count == 5:
exit(f'\n在下载{stock_code}时失败,程序终止')
else:
sleep_time += 1
else:
break
if df.empty: #如果下载的数据为空,则可能被反爬管控,也有可能这段时间没有开盘
self.lock.acquire()
self.empty_list.append(stock_code)
self.stock_code_list.remove(stock_code)
self.lock.release()
return
# 数据写入文件
path = os.path.join(stock_path, stock_code + '.csv') # 构建存储文件路径
df.to_csv(path, index=False, encoding='gbk') # 直接生成文件
self.lock.acquire()
self.stock_code_list.remove(stock_code)
self.finished_num += 1
self.lock.release()
# ==== 下载个股数据_并行多进程
def updateStock(self):
# ==== 从网易财经上获取股票数据,构造url
url = r'http://quotes.money.163.com/service/chddata.html?'
title = 'TCLOSE;HIGH;LOW;TOPEN;LCLOSE;VOTURNOVER;VATURNOVER;TCAP;MCAP' # 要请求什么字段,见下面注释
task_list = self.stock_code_list
code_urls = [] # 将所有股票的下载链接存入
for stock_code in task_list: # 构造url 并存入code_urls
if stock_code.startswith('sh'):
code = '0' + stock_code[2:]
else:
code = '1' + stock_code[2:]
download_url = url + 'code=' + code + '&start=' + self.start_date + '&end=' + self.end_date + '&fields=' + title
code_urls.append([stock_code, download_url])
pool = ThreadPoolExecutor(self.threading_num) # 构造线程池
all_task = [pool.submit(self.updateStock_pool_per,code_url) for code_url in code_urls] # 将所有线程添加到任务列表
for future in as_completed(all_task): # 每完成一个线程就输出一次进度。future.result可以用于接收函数的返回值。
print('\r' + f'共{self.total_stock_num}支股票,已完成{self.finished_num}支的下载', end='', flush=True) # 打印进度
# ==== 以下为结果报告
print('\n已完成个股数据的下载')
if self.empty_list:
print(f'以下股票没有获取数据,请确认自{self.start_date}以来是否停牌')
print(self.empty_list)
if self.stock_code_list:
print(f'由于未知原因,以下股票未能完成下载')
# ==== 以下为主程序
def main(self):
t1 = datetime.datetime.now() # 记录程序开始时间,用于计算总体用时
self.getStockDataFromSina()
self.updateStock()
print(f'程序已运行完毕,总用时{str(datetime.datetime.now()-t1)[:-7]}')
if __name__ == '__main__':
# 以下3个参数自己更改
stock_path = r'E:\stock' # 本地个股数据的储存文件夹地址
user_agent = ''
threading_num = 12 # 设定线程数
a = UpdateStockData(stock_path,user_agent,threading_num)
a.main()
在pycharm上运行偶尔会出现这种现象,就是一直卡住不动,两个小时后依然如此。
这种现象大多数出现在获取最后一个数据的时候。如果是被反爬的话,它不会只反我一个线程啊
帮我看看是哪里写得不对导致这种问题?如果是网站的问题,是否有其他网址可以爬取这种数据?很多财经网站都有,但都是复权后的数据,或者没有“前收盘价”这个关键数据。我要的是[日期,开盘价,最高价,最低价,收盘价,前收盘价]这些价格都是不复权的。不胜感激!
你这情况可能是被反爬了,建议如下:
他们说的对你被反扒了 使用代理或者是模拟点击 使用selenium js 结合的方式 https://dongfangyou.blog.csdn.net/article/details/127156948