本文来源吾爱破解论坛
如果帖子存在违规,麻烦删除,谢谢。前言:
本人先前没有接触python,所以以下所写代码如果有误,请各位大大不吝赐教,万分感谢。
打算学习python是因为一位论坛贴“股价翻番 人生赢家,python爬取基金 筛选股票”,传送门:https://www.52pojie.cn/thread-1086853-1-1.html 。看了这个帖子,发现python对于网页的处理好方便啊,如果换成VC来搞,需要自己处理的地方太多太多了。以前总是看别人爬虫,这个帖子写的也很详细,果断入手python,小白一枚,初次练习,如有错误,还望指正。
正文:
原贴中获取基金的持仓数据,再此说明一下,获取的持仓数据并非实时,如果有炒股的看到,老股民也就罢了,新股民慎用提取出来的数据,慎用!慎用!慎用!
优化思路:
1、原代码支持提取了基金的持仓股票的名称。
优化增加股票的持仓量数据,可以练习提取数据操作。
2、原代码是单线程
效率太低,要跑好几个小时。实现多线程处理,优化速度。
3、原代码打印执行进度无法知道采集进度
增加进度条显示
实现1:
[Python] 纯文本查看 复制代码
# selenium请求[基金持仓股票详情页面url]的方法,爬取基金的持仓股票名称、持仓量; def hold_a_position(url): stock_name = [] # 定义一个数组,存储证券的名称 amount = [] #定义一个数组,存储证券的持仓 # 浏览器动作 chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless') chrome_options.add_argument('--disable-gpu') driver = webdriver.Chrome(options=chrome_options) # 初始化浏览器,无浏览器界面的,保持后台运行; driver.get(url) # 请求基金持仓的信息 element_result = is_element(driver, "tol") # 是否存在这个元素,用于判断是否有持仓信息; #print(url + '\n') if element_result == True: # 如果有持仓信息则爬取; wait = WebDriverWait(driver, 3) # 设置一个等待时间 input = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'tol'))) # 等待这个class的出现; ccmx_page = driver.page_source # 获取页面的源码 ccmx_xpath = etree.HTML(ccmx_page) # 转换成成 xpath 格式 trs = ccmx_xpath.xpath("//div[@class='txt_cont']//div[@id='cctable']//div[@class='box'][1]//tr") if trs: #print("开始获取基金持仓信息") for tr in trs: stock_name_t = tr.xpath("./td[3]//text()") if len(stock_name_t) != 0: #获取成功才返回数据 stock_amount_t = tr.xpath("./td[8]//text()") if len(stock_amount_t) != 0: stock_amount = stock_amount_t[0].replace(",", "") #去除持仓中的逗号 if stock_amount.split(".")[-1].isdigit(): #如果是数值则继续,此处还待优化,仍有字母数据返回 stock_name.append(stock_name_t[0]) amount.append(stock_amount) #print(stock_name) #print(amount) driver.quit() return stock_name,amount else: # 如果没有持仓信息,则返回null字符; driver.quit() return "null","null"
原代码中获取股票名称是:ccmx_xpath.xpath("//div[@class='txt_cont']//div[@id='cctable']//div[@class='box'][1]//td[3]//text()")
找了xpath的说明,还是不知道一行代码怎么获取股票名称和持仓量,只能本办法分开获取,写入两个数组了。
代码执行过程中发现12g的内存被吃满了,对于我的办公机太严苛了,看进程,发现chromedriver为什么那么多,果断取消执行,度娘后发现原代码的driver.Close()引起的,改为driver.quit(),重新执行后正常。资料:https://blog.csdn.net/yangfengjueqi/article/details/84338167
实现2:
[Python] 纯文本查看 复制代码
if __name__ == '__main__': fund_url, fund_name = page_url() # 获取首页数据,返回基金url的数组和基金名称的数组; if len(fund_url) == len(fund_name): # 判断获取的基金url和基金名称数量是否一致 threadNum = 10 #线程数量 all_count=len(fund_url) #基金数量 threadId = 1 #线程ID threads = [] #线程集合 #开启多线程 for tName in range(threadNum): thread = myThread(threadId,("Thread-%d" % tName),fund_url, fund_name, round(all_count*(threadId-1)/threadNum+1), round(all_count*threadId/threadNum)) thread.start() threads.append(thread) threadId += 1 #显示进度条 while nPos<all_count: progress_bar(nPos,all_count) time.sleep(5) # 等待所有线程完成 for t in threads: t.join() print("退出主线程") #保险起见,关闭所有的chrome进程 os.system('taskkill /im chromedriver.exe /F') os.system('taskkill /im chrome.exe /F') else: print("基金url和基金name数组数量不一致,退出。") exit()
[Python] 纯文本查看 复制代码
#多线程class myThread (threading.Thread): def __init__(self, threadID, name,fund_url, fund_name, begin_num, end_num): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.fund_url = fund_url self.fund_name = fund_name self.begin_num = begin_num self.end_num = end_num def run(self): print ("开始线程:" + self.name) Get_stock_detail(self.fund_url, self.fund_name, self.begin_num, self.end_num) print ("退出线程:" + self.name)
[Python] 纯文本查看 复制代码
#多线程获取基金持仓明细入口,begin_num是基金列表的开始位置,end_num是基金列表的结束位置 def Get_stock_detail(fund_url, fund_name, begin_num, end_num): #初始化mysql连接 mydb = mysql.connector.connect( host="10.23.1.132", user="root", passwd="abc123", database="ofstock" ) cursor = mydb.cursor() while begin_num < end_num: global nPos nPos += 1 #用于进度条显示 stock_name, amount = hold_a_position(fund_url[begin_num]) # 遍历持仓信息,返回持仓股票名称、持仓量---数组 for j in range(len(stock_name)): sql = "INSERT INTO ofstockinfo (fund_url, fund_name, stock_name, amount) VALUES (%s, %s, %s, %s)" % ( repr(fund_url[begin_num]), repr(fund_name[begin_num]), repr(stock_name[j]), repr(amount[j])) try: cursor.execute(sql) mydb.commit() #print("插入记录成功") except Exception as e: mydb.rollback() print(e.args, "插入记录失败") begin_num += 1 mydb.close()
我设置的是10个线程,速度一般吧,但是我的机器的cpu差不多100%,还好不是一直100%,凑合半个多小时差不多跑完。
另外原代码用的是mongodb,我在win2008机器装不上!!!进度卡在70%左右,放弃了,改用mysql,后面再研究吧。
实现3:
[Python] 纯文本查看 复制代码
#进度条实现def progress_bar(portion, total): """ total 总数据大小,portion 已经传送的数据大小 :param portion: 已经接收的数据量 :param total: 总数据量 :return: 接收数据完成,返回True """ part = total / 50 # 1%数据的大小 count = math.ceil(portion / part) sys.stdout.write('\r') sys.stdout.write(('[%-50s]%.2f%%' % (('>' * count), portion / total * 100))) sys.stdout.flush() if portion >= total: sys.stdout.write('\n') return True
这是网上找的,是哪里的,嘿嘿,忘了!!原谅我厚颜无耻吧。
整体实现完成,用到的python的是多进程、xpath、mysql等吧,初次接触,如果有什么错误,还望不吝赐教。跑下来数据还是存在有问题的数据,需要对结果处理下,语句:delete from ofstockinfo where amount not REGEXP '(^[0-9]+.[0-9]+$)|(^[0-9]$)'
忘记了,提上表结构:"CREATE TABLE ofstockinfo (fund_url VARCHAR(255), fund_name VARCHAR(100),stock_name VARCHAR(100),amount VARCHAR(100))"
下载:
下载积分: 吾爱币 -1 CB
版权声明:
本站所有资源均为站长或网友整理自互联网或站长购买自互联网,站长无法分辨资源版权出自何处,所以不承担任何版权以及其他问题带来的法律责任,如有侵权或者其他问题请联系站长删除!站长QQ754403226 谢谢。