from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from lxml import etree
from time import sleep
import pandas as pd
from bs4 import BeautifulSoup
def get_row(li):
list1 = []
l1_1 = li.find_all('a', limit=2)
l1_2 = li.find_all('th')
for x in l1_1:
list1.append(x.string)
for y in l1_2:
list1.append(y.string)
return list1
# 实例化一个浏览器对象
wd = webdriver.Chrome(executable_path='./chromedriver')
# 让浏览器发起一个指定url的请求
wd.get('http://vip.stock.finance.sina.com.cn/fund_center/index.html#hbphall')
# 设置隐式等待时间
wd.implicitly_wait(20)
# 获取浏览器当前界面的动态页面源码数据
page_text = wd.page_source
# 解析企业名称
soup = BeautifulSoup(page_text, "html.parser")
# 建立空列表
list_ji = []
### 最大页码
max_page = wd.find_element(By.XPATH,'//*[@id="pHBPH"]/a[3]').text
### 检测测数据是否加载完成
def data_exsist():
# 获取浏览器当前界面的动态页面源码数据
page_text = wd.page_source
# 解析企业名称
soup = BeautifulSoup(page_text, "html.parser")
if soup.find_all('tr',class_='red') :
global list_ji
l1 =soup.find_all('tr',class_ = 'red')
for j in range(0,40) :
list_ji.append(get_row(l1[j]))
else:
time.sleep(10)
if soup.fin_all('tr', class_='red'):
l1 = soup.find_all('tr', class_='red')
for j in range(0, 40, 1):
list_ji.append(get_row(l1[j]))
else:
wd.refresh()
time.sleep(5)
data_exsits()
### 主程序
def get_all_data() :
global wd,list_ji ###声明全局变量
for i in range(1,int(max_page)+1) :
if i != int(max_page)-1 :
data_exsist()
print(f'当前第{i}页')
wd.find_element(By.LINK_TEXT, '下一页').click()
else :
l1 = soup.find_all('tr', class_='red')
for line in (0,40) :
try :
list_ji.append(get_row(l1[j]))
except Exception :
break
###报错就说明所有数据都拿完了,直接退出即可
get_all_data()
column = ["基金代码", "基金名称", "单位净值", "累计净值", "近三个月(%)", "近六个月(%)", "近一年(%)",
"今年以来(%)", "成立以来(%)"]
result = pd.DataFrame(list_ji, columns=column)
pd.set_option('display.max_rows', None) # 显示pandas所有行
# result.columns = ["基金代码", "基金名称", "单位净值", "累计净值", "近三个月(%)", "近六个月(%)", "近一年(%)", "今年以来(%)", "成立以来(%)"]
print(result)
wd.quit()
总是爬取到331页就没法继续了,请求帮助。
当前页提取列表数据超出索引,这也不是什么报错,当你列表里面没东西或者索引值超过了列表元素的时候就会出现这个问题,
就是你爬到的这页,抓取的这个列表值,里面没东西或者东西太少。所以报错了。
建议你换个网站爬取那个年份的内容或者就忽略掉它,看看这个网站331页的结构,重新编写爬虫程序。
你需要提供报错等信息啊
上次是不是也是你发的这个,有好的方式为啥非要这么爬取呢。真想不通!!!一大堆代码,还爬不下来。
这么大量的数据,用selenium 爬确实服了!
可以直接分析接口,数据都在接口里面,不用爬页面,就可以返回数据了,结合正则表达式,就可以获取数据了
# pip install openpyxl
import requests,re
from time import sleep
import pandas as pd
def getFundData(page,num=100):
'''爬虫函数'''
# http://vip.stock.finance.sina.com.cn/fund_center/index.html#hbphall
url = "http://vip.stock.finance.sina.com.cn/fund_center/data/jsonp.php/IO.XSRV2.CallbackList['dxJ_DCLDxQnQYM8a']/NetValueReturn_Service.NetValueReturnOpen"
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
'Refer':'http://vip.stock.finance.sina.com.cn/fund_center/index.html',
'Host':'vip.stock.finance.sina.com.cn'
}
payload={
'page': page,
'num': num, #这个是每页返回的数量,可以自己定义,页面上给的是40,我这边调整成100了,不建议弄成太大的
'sort': 'form_year',
'asc': 0,
'type2': 0
}
result = requests.get(url=url,headers=headers,params=payload).content.decode('utf-8')
# print(result) #这里面可以看到总数,也就是total_num
#通过正则把需要的数据过滤出来,并返回
regex = re.compile(r'"total_num":\d+,"data":(\[\{"symbol.*?\}\]),"exec_time')
data = regex.findall(result)[0]
data = eval(data)
return data
if __name__ == '__main__':
total_num = 16742 #这个是在请求的返回值中看到的
num = 100 #自定义返回的数量,页面上给的是40
total_data = []
# 计算总页码
total_page,other = divmod(total_num,num)
#如果余数大于0,总页数就 +1
if other>0:
total_page = total_page +1
# print(total_page)
#请求接口,获取数据
for page in range(1,total_page+1):
data = getFundData(page=page,num=num)
total_data.extend(data)
sleep(5) #防止爬取太快,封IP,所以有个sleep
# print(len(total_data))
# column暂时没用到,因为返回的数据是列表,列表中是一个个的字典
# column = ["基金代码", "基金名称", "单位净值", "累计净值", "近三个月(%)", "近六个月(%)", "近一年(%)","今年以来(%)", "成立以来(%)"]
if total_data:
df = pd.DataFrame(total_data)
df.to_excel('result.xlsx',index=False)