目录
- 项目概述
- 代码解释
- 遇到的问题
1. 项目概述
本项目旨在利用Python中的Selenium库和MongoDB数据库,实现对东财网站股票数据的自动爬取。通过多线程技术提高爬取效率,将提取到的股票信息(如代码、名称、最新价等)存储到MongoDB,以便后续分析和使用。该项目不仅展示了数据爬取的基本流程,还强调了数据存储的高效性。
2. 代码解释
项目的核心代码主要由几个部分组成:
2.1 环境配置
首先,使用pymongo
连接到本地MongoDB数据库,并创建一个名为stock_data
的数据库和stocks
集合来存储爬取的数据。Selenium配置Chrome浏览器选项,禁用通知,以确保浏览器操作的顺利进行。
from pymongo import MongoClient
# MongoDB连接
client = MongoClient('localhost', 27017)
db = client['stock_data']
collection = db['stocks']
2.2 数据提取函数
fetch_data
函数是数据爬取的主函数,通过传入起始页和结束页来控制爬取的范围。它包含以下几个重要步骤:
def fetch_data(start_page, end_page):
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
try:
for page in range(start_page, end_page + 1):
print(f"线程 {threading.current_thread().name} 正在爬取第 {page} 页的数据...")
driver.get("http://quote.eastmoney.com/center/gridlist.html#hs_a_board")
# 动态等待数据加载
dynamic_wait(driver)
# 滚动页面,直到不能再滚动
dynamic_scroll(driver)
# 获取数据
rows = driver.find_elements(By.XPATH, "//tbody/tr")
for row in rows:
data = {
"序号": row.find_element(By.XPATH, "./td[1]").text,
"代码": row.find_element(By.XPATH, "./td[2]").text,
"名称": row.find_element(By.XPATH, "./td[3]").text,
"最新价": row.find_element(By.XPATH, "./td[5]").text,
"涨跌幅": row.find_element(By.XPATH, "./td[6]").text,
"涨跌额": row.find_element(By.XPATH, "./td[7]").text,
"成交量": row.find_element(By.XPATH, "./td[8]").text,
"成交额": row.find_element(By.XPATH, "./td[9]").text,
"振幅": row.find_element(By.XPATH, "./td[10]").text,
"最高价": row.find_element(By.XPATH, "./td[11]").text,
"最低价": row.find_element(By.XPATH, "./td[12]").text,
"今开价": row.find_element(By.XPATH, "./td[13]").text,
"昨收价": row.find_element(By.XPATH, "./td[14]").text,
"量比": row.find_element(By.XPATH, "./td[15]").text,
"换手率": row.find_element(By.XPATH, "./td[16]").text,
"市盈率(PE)": row.find_element(By.XPATH, "./td[17]").text,
"市净率(PB)": row.find_element(By.XPATH, "./td[18]").text,
}
# 保存到MongoDB
try:
collection.insert_one(data)
except Exception as e:
print(f"插入数据时出错: {e}")
# 点击下一页
try:
next_page = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//*[@id='main-table_paginate']/a[contains(text(), '下一页')]"))
)
next_page.click()
time.sleep(2) # 等待页面加载
except Exception as e:
print(f"点击下一页时出错: {e}")
break # 出错后退出循环
finally:
driver.quit()
2.3 动态等待与滚动
dynamic_wait
函数用于动态等待页面元素的加载,最大等待时间为10秒。dynamic_scroll
函数实现页面滚动,确保加载到全部数据。
def dynamic_wait(driver):
"""动态等待页面加载"""
wait_time = 1
max_wait_time = 10
while wait_time <= max_wait_time:
try:
WebDriverWait(driver, wait_time).until(
EC.presence_of_element_located((By.XPATH, "//tbody/tr"))
)
break
except:
wait_time += 1
time.sleep(1)
def dynamic_scroll(driver):
"""动态滚动页面"""
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
2.4 多线程处理
项目通过创建10个线程实现并行爬取,每个线程负责爬取一定数量的页面,显著提高了数据获取效率。
# 创建线程
threads = []
page_per_thread = 10
for i in range(10):
start_page = i * page_per_thread + 1
end_page = start_page + page_per_thread - 1
thread = threading.Thread(target=fetch_data, args=(start_page, end_page), name=f'Thread-{i + 1}')
threads.append(thread)
# 启动线程
for thread in threads:
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
print("数据爬取完成,已保存到MongoDB。")
3. 遇到的问题
在项目实施过程中,遇到了几个主要问题:
-
数据插入失败:在尝试将数据保存到MongoDB时,可能由于网络问题或MongoDB未启动导致插入失败。通过增加异常处理,能够捕获并打印错误信息。
-
点击元素失败:在执行翻页操作时,出现了元素不可点击的错误。这可能由于页面加载不完全或按钮被其他元素覆盖。为此,使用了显式等待来确保按钮在可点击状态后再执行点击。
-
动态等待:初始代码中动态等待的逻辑存在不足,可能导致在数据未完全加载时就进行操作。通过优化等待机制,确保了数据的准确性。
总结
本项目通过结合Selenium和MongoDB,实现了对股票数据的自动化爬取,展示了如何处理动态网页数据。通过多线程技术有效提高了爬取效率,同时解决了在数据存储和页面交互中遇到的问题,为进一步的数据分析奠定了基础。未来可以考虑引入更复杂的错误处理机制及数据分析功能,以提升系统的可靠性和实用性。