python爬虫爬取可转债教程
前几天发布了可转债爬取,有些同学一直想要源码:今天来展示一下爬取的过程:第一先是建立可转债类:
class ConvertibleBond(object): def __init__(self, datas):
# 转债代码
self.bond_id = datas['bond_id']
# 转债名称
self.bond_nm = datas['bond_nm']
# 正股代码
self.stock_id = datas['stock_id']
# 正股名称
self.stock_nm = datas['stock_nm']
#
self.btype = datas['btype']
# 转股价
self.convert_price = datas['convert_price']
#
self.convert_price_valid_from = datas['convert_price_valid_from']
self.convert_dt = datas['convert_dt']
# 到期时间
self.maturity_dt = datas['maturity_dt']
# 正股价
self.sprice = datas['sprice']
# 现价
self.price = datas['price']
# 到期税前收益率
self.ytm_rt = datas['ytm_rt']
# 剩余年限
self.year_left = datas['year_left']
# 双低
self.dblow = datas['dblow']
# 强赎触发价
self.force_redeem_price = datas['force_redeem_price']
# 回售触发价
self.put_convert_price = datas['put_convert_price']
# 溢价率
self.premium_rt = datas['premium_rt']
# 到期税后收益
self.ytm_rt_tax = datas['ytm_rt_tax']
# 剩余规模
self.orig_iss_amt = datas['orig_iss_amt']
# 建仓线
self.build = None
# 加仓线
self.plus = None
# 重仓线
self.Multiple = None
# 评级
self.rating_cd = datas['rating_cd']
# 操作
self.cz = None
# 基准
self.jz_rate = None
self.sh_price = None
self.dq_price = None
self.sum_lixi = 0
这样做的好处就是拿到类就可以拿到这个可转债的所有的数据,便于后期分析,而不用总是去用列表加来加去。
2从集思录获取可转债的详情页面里面的可转债到期价值。
def getdarse(self):
darse_url = 'https://www.jisilu.cn/data/convert_bond_detail/' + self.bond_id
darse_resp = requests.get(darse_url)
html = darse_resp.content.decode('utf-8')
lixi = re.findall(r'''
<td.+?cpn_desc".+?>(.+?)</td>
''', html, re.VERBOSE)
try:
lixi = re.findall('.+?(\d+\.\d+).*?', lixi)
for i in range(len(lixi) - 1):
self.sum_lixi = self.sum_lixi + float(lixi)
self.sh_price = float(re.findall('<td.+?redeem_price.+?\n(.+?)</td>', html).strip())
self.dq_price = self.sh_price + self.sum_lixi * 0.8
self.build = float(self.dq_price) - (float(self.year_left) * 2.5)
self.plus = float(self.dq_price) - (float(self.year_left) * 4)
self.Multiple = float(self.dq_price) - (float(self.year_left) * 6)
self.jz_rate = (self.build - float(self.price)) / float(self.price)
except:
pass
try:
if float(self.price) <= self.build:
self.cz = '建仓'
if float(self.price) <= self.plus:
self.cz = '加仓'
if float(self.price) <= self.Multiple:
self.cz = '重仓'
except:
pass
建仓线就是年化收益2.5来计算的,以这个价格买进去最差就是持有到可转债到期,我们的收益就是年化2.5,同理类推加仓线以及重仓线。
3.重点来了:
怎么获取这些数据呢,我们打开集思录可转债页面
https://www.jisilu.cn/data/cbnew/#cb
然后打开检查。
用requests获得数据。
获得数据后我们就可以把数据传给可转债类,并且根据数据进行筛选
要求评级必须在AA以上,可转债的现价要低于110元,可转债的剩余年限要小于5.5,就是说要发布半年后,双低要小于125
opt = ['AAA', 'AA+', 'AA']if cb.build != None and cb.rating_cd in opt and float(cb.price) <= 110 and float(cb.year_left) < 5.5 and float(
cb.dblow) < 125:
cbs.append(cb)
根据到期收益率筛选前50名可转债
cbs.sort(key=lambda x: x.jz_rate, reverse=True)
cbs1 = cbs[:50]
根据溢价率筛选前30名可转债
cbs1.sort(key=lambda x: float(x.premium_rt[:-1]) * 0.01, reverse=False)
cbs2 = cbs1[:30]
最后根据筛选好的目录写入csv文件
def wirte_csv(cbs, name):
f = open(f'{name}.csv', 'w', encoding='utf-8', newline='')
csv_writer = csv.writer(f)
csv_writer.writerow(["代 码", "转债名称", "现 价", "正股名称", "正股价格", "建仓线", "加仓线", "重仓线", "溢价率", "评级",
"回售触发价", "强赎触发价", "剩余年限", "双低", "操作"])
for cb in cbs:
csv_writer.writerow([cb.bond_id, cb.bond_nm, cb.price, cb.stock_nm, cb.sprice, cb.build, cb.plus, cb.Multiple,
cb.premium_rt, cb.rating_cd, cb.put_convert_price, cb.force_redeem_price, cb.year_left,
cb.dblow, cb.cz])
f.close()
完成,欢迎小伙伴留言交流,根据情况可以做基金筛选的爬虫。可以私聊我给出自己的策略,我来写代码 已经摊大饼半年多了,刚需啊,只不过不懂代码{:1_907:} molinchz 发表于 2021-12-4 09:33
能分享下源码不,我的跑不起来。
这是多线程的。import requests
import re
import time
import csv
import pandas as pd
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Pool
today = time.strftime("%Y-%m-%d", time.localtime())
# 建立可转债类,这样做的好处就是拿到类就可以拿到这个可转债的所有的数据,便于后期分析,而不用总是去用列表加来加去
class ConvertibleBond(object):
def __init__(self, datas):
# 转债代码
self.bond_id = datas['bond_id']
# 转债名称
self.bond_nm = datas['bond_nm']
# 正股代码
self.stock_id = datas['stock_id']
# 正股名称
self.stock_nm = datas['stock_nm']
#
self.btype = datas['btype']
# 转股价
self.convert_price = datas['convert_price']
#
self.convert_price_valid_from = datas['convert_price_valid_from']
self.convert_dt = datas['convert_dt']
# 到期时间
self.maturity_dt = datas['maturity_dt']
# 正股价
self.sprice = datas['sprice']
# 现价
self.price = datas['price']
# 到期税前收益率
self.ytm_rt = datas['ytm_rt']
# 剩余年限
self.year_left = datas['year_left']
# 双低
self.dblow = datas['dblow']
# 强赎触发价
self.force_redeem_price = datas['force_redeem_price']
# 回售触发价
self.put_convert_price = datas['put_convert_price']
# 溢价率
self.premium_rt = datas['premium_rt']
# 到期税后收益
self.ytm_rt_tax = datas['ytm_rt_tax']
# 剩余规模
self.orig_iss_amt = datas['orig_iss_amt']
# 建仓线
self.build = None
# 加仓线
self.plus = None
# 重仓线
self.Multiple = None
# 评级
self.rating_cd = datas['rating_cd']
# 操作
self.cz = None
# 基准
self.jz_rate = None
self.sh_price = None
self.dq_price = None
self.sum_lixi = 0
# 从集思录获取可转债的详情页面里面的可转债到期价值
def getdarse(self):
darse_url = 'https://www.jisilu.cn/data/convert_bond_detail/' + str(self.bond_id)
darse_resp = requests.get(darse_url)
html = darse_resp.content.decode('utf-8')
lixi = re.findall(r'''
<td.+?cpn_desc".+?>(.+?)</td>
''', html, re.VERBOSE)
try:
lixi = re.findall('.+?(\d+\.\d+).*?', lixi)
for i in range(len(lixi) - 1):
self.sum_lixi = self.sum_lixi + float(lixi)
self.sh_price = float(re.findall('<td.+?redeem_price.+?\n(.+?)</td>', html).strip())
self.dq_price = self.sh_price + self.sum_lixi * 0.8
self.build = float(self.dq_price) - (float(self.year_left) * 2.5)
self.plus = float(self.dq_price) - (float(self.year_left) * 4)
self.Multiple = float(self.dq_price) - (float(self.year_left) * 6)
self.jz_rate = (self.build - float(self.price)) / float(self.price)
except:
pass
try:
if float(self.price) <= self.build:
self.cz = '建仓'
if float(self.price) <= self.plus:
self.cz = '加仓'
if float(self.price) <= self.Multiple:
self.cz = '重仓'
except:
pass
def get_data():
UA = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
headers = {'User_Agent': UA}
url ='https://www.jisilu.cn/data/cbnew/cb_list/?___jsl=LST___t=1620267814804'
#最的简单的header字段,防止部分网址反爬虫机制
response=requests.get(url,headers=headers)
#当爬取的界面需要用户名密码登陆的时候,构件的请求需要包含auth字段
data=response.json()
rows=data['rows']
return rows
# 最后根据筛选好的目录写入csv文件
def wirte_csv(cbs, name):
f = open(f'{name}.csv', 'w', encoding='utf-8', newline='')
csv_writer = csv.writer(f)
csv_writer.writerow(["代 码", "转债名称", "现 价", "正股名称", "正股价格", "建仓线", "加仓线", "重仓线", "溢价率", "评级",
"回售触发价", "强赎触发价", "剩余年限", "双低", "操作"])
for cb in cbs:
csv_writer.writerow([cb.bond_id, cb.bond_nm, cb.price, cb.stock_nm, cb.sprice, cb.build, cb.plus, cb.Multiple,
cb.premium_rt, cb.rating_cd, cb.put_convert_price, cb.force_redeem_price, cb.year_left,
cb.dblow, cb.cz])
f.close()
def wirte_xls(cbs):
data_list = []
for cb in cbs:
data=
data_list.append(data)
df = pd.DataFrame(data_list) #以数组方式写入
df.columns = ["代 码", "转债名称", "现 价", "正股名称", "正股价格", "建仓线", "加仓线", "重仓线", "溢价率", "评级","回售触发价", "强赎触发价", "剩余年限", "双低", "操作"]
# print(df)
df[["代 码", "现 价", "正股价格", "建仓线", "加仓线", "重仓线","强赎触发价", "剩余年限", "双低"]] = df[
["代 码", "现 价", "正股价格", "建仓线", "加仓线", "重仓线","强赎触发价", "剩余年限", "双低"]].astype(float)
#,dtype = {"代 码' : float,"现 价' : float,"正股价格" : float,"建仓线": float, "加仓线": float, "重仓线": float, "溢价率": float, "回售触发价": float, "强赎触发价": float, "剩余年限": float}
#df.apply(pd.to_numeric, errors='ignore')
#df = df.infer_objects()
df.to_excel('./筛选可转债.xlsx',sheet_name=today,index=False)
print("=====================================已全部导出!=====================================")
def data(datas):
data = datas['cell']
cb = ConvertibleBond(data)
cb.getdarse()
opt = ['AAA', 'AA+', 'AA']
if cb.build != None and cb.rating_cd in opt and float(cb.price) <= 110 and float(cb.year_left) < 5.5 and float(cb.dblow) < 125:
return cb
if __name__ == "__main__":
start = time.time()
cbs = []
bs = []
t = ThreadPoolExecutor(max_workers=10)
for datas in t.map(data, get_data()):
if datas!=None:
cbs.append(datas)
# 根据到期收益率筛选前50名可转债
print(list(cbs))
cbs.sort(key=lambda x: x.jz_rate, reverse=True)
cbs1 = cbs[:50]
# 根据溢价率筛选前30名可转债
cbs1.sort(key=lambda x: float(x.premium_rt[:-1]) * 0.01, reverse=False)
cbs2 = cbs1[:30]
cbs2.sort(key=lambda x: float(x.price), reverse=False)
# print(cbs2)
wirte_xls(cbs2)
# wirte_csv(cbs2)
# print("爬取完成")
end = time.time()
print(end - start)
Python有没有可以设置任意请求头且可以模拟网页按钮点击的 感谢分享,学习学习 鸭子咯咯哒~ 发表于 2021-5-4 15:29
Python有没有可以设置任意请求头且可以模拟网页按钮点击的
可以模拟按钮点击的selenium 麦子1995 发表于 2021-5-4 15:27
大佬,来个全部完成的代码呗
可以给我你的要求,我来给你写代码 miracle2016 发表于 2021-5-4 15:34
可以给我你的要求,我来给你写代码
比如用fiddler抓取百度的请求头,
要求用 selenium 来 添加所有的请求头
这个咋写
好像不能添加cookie这个请求? 鸭子咯咯哒~ 发表于 2021-5-4 15:36
比如用fiddler抓取百度的请求头,
要求用 selenium 来 添加所有的请求头
这个咋写
selenium输入账号密码就好了,干嘛用cookie 这是干货啊 miracle2016 发表于 2021-5-4 15:43
selenium输入账号密码就好了,干嘛用cookie
我的这个是微信的,不晓得咋登录啊只能获取登录的cookie,但是又不晓得咋获取