一.需要采集的页面是涨跌幅排行_数据中心_同花顺财经所有上市公司股票信息,以及所属概念板块。使用Edge浏览器进行采集。

二.检查页面

1.进入页面涨跌幅排行_数据中心_同花顺财经,按F12打开检查。
在这里插入图片描述

2.进入检查后,先点击网络(第1步),这时候下方应该会刷新出“1/”,如果没有刷新出来,就点击左下方第一页(第2步),此时就会刷新出来。然后打开“1/”(第3步)。
在这里插入图片描述

3.打开“1/”后,可以找到相关URL、请求标头、响应标头等信息,重点看黄色框标注的信息,在采集程序时要配置这些参数。之后进行代码的编写。
在这里插入图片描述
在这里插入图片描述

三.试着先采集第一页内容看看

1.导入库

import requests
import parsel
from lxml import etree
import time
import random
import execjs
import pandas as pd
import pickle

2.配置URL、请求头参数。

新建三个变量headers、url、page_cookie,将在检查中找到的内容对号入座赋值给三个变量。

headers = {
    "User-Agent": "************************************************************",
    "Accept-Encoding": "gzip, deflate, br",
    }  
url = f"https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/1/free/1/"
page_cookie = {
    "v": "A3qivkkdxq0YZUrBCY0TqtC5y6uZK_gvcK5ypoRzJz3anxSVbLtOFUA_wrpX"
}

3.尝试发送请求,并打印获取到的html。

session = requests.Session()
response = session.get(url = url, headers = headers, cookies = page_cookie, timeout = 10, verify = False)
response.encoding = "gbk"
html = response.text
print(html)

4.与个股相关的内容如下,内容太长了,所以只演示一只股票。

<tr >
    <td class="first tc">4</td>
    <td class="tc "><a href="http://stockpage.10jqka.com.cn/300801/" target="_blank">300801</a></td>
    <td class="tc"><a href="http://stockpage.10jqka.com.cn/300801/"  target="_blank" code="hs_300801" class="J_showCanvas">泰和科技</a></td>
    <td class="tr c-rise ">20.90</td>
    <td class="tr c-rise cur">15.92</td>
    <td class="tr c-rise ">23.30</td>
    <td class="tr c-rise ">22.49</td>
    <td class="tr c-rise ">22.80</td>
    <td class="tr c-rise ">46.27</td>
    <td class="tr c-rise ">50.49</td>
    <td class="tr c-fall ">-793.91万</td>
    <td class="tr c-rise ">4986.50万</td>
    <td class="tr c-rise ">4963.21万</td>
</tr>

4.因为所有与个股相关的部分都在子节点下,使用xpath对子节点的内容进行解析。

html_tree = etree.HTML(html)
stock_list = html_tree.xpath("//table[@class='m-table J-ajax-table']/tbody/tr")

5.获得所有子节点,并存放在变量stock_list中。

[<Element tr at 0x2312fab9100>,
 <Element tr at 0x2312fab8e40>,
 <Element tr at 0x2312fab8ec0>,
 <Element tr at 0x2312fab9140>,
 <Element tr at 0x2312fab91c0>,
 <Element tr at 0x2312fab9400>,
 <Element tr at 0x2312fab9240>,
 <Element tr at 0x2312fab9440>,
 <Element tr at 0x2312fab93c0>,
 <Element tr at 0x2312fab8f40>,
 <Element tr at 0x2312fab9340>,
 <Element tr at 0x2312fab92c0>,
 <Element tr at 0x2312fab9300>,
 <Element tr at 0x2312fab9480>,
 <Element tr at 0x2312fab9640>,
 <Element tr at 0x2312fab8800>,
 <Element tr at 0x2312fab8e00>,
 <Element tr at 0x2312fab95c0>,
 <Element tr at 0x2312fab99c0>,
 <Element tr at 0x2312fab9580>,
 <Element tr at 0x2312fab98c0>,
 <Element tr at 0x2312fab9940>,
 <Element tr at 0x2312fab9a00>,
 <Element tr at 0x2312fab9a40>,
 <Element tr at 0x2312fab9a80>,
...
 <Element tr at 0x2312fab8640>,
 <Element tr at 0x2312fab9f40>,
 <Element tr at 0x2312fab9600>,
 <Element tr at 0x2312fab8f00>,
 <Element tr at 0x2312fab9f80>]

6.进一步解析每个,以获得个股代码以及股票简称,将解析出的内容存入列表stock。

stocks = []
for stock in stock_list:
    # 从列表中获取第一个元素,如果列表为空则返回None
    code = stock.xpath(".//td[2]/a/text()")
    code = code[0] if code else None
    
    name = stock.xpath(".//td[3]/a/text()")
    name = name[0] if name else None
    # 存储为字典
    stocks.append({
        "代码": code,
        "简称": name
    }) 

7.列表stock。

[{'代码': '301421', '简称': '波长光电'},
 {'代码': '300515', '简称': '三德科技'},
 {'代码': '300172', '简称': '中电环保'},
 {'代码': '300801', '简称': '泰和科技'},
 {'代码': '301219', '简称': '腾远钴业'},
 {'代码': '301176', '简称': '逸豪新材'},
 {'代码': '300072', '简称': '海新能科'},
 {'代码': '300531', '简称': '优博讯'},
 {'代码': '301003', '简称': '江苏博云'},
 {'代码': '301213', '简称': '观想科技'},
 {'代码': '300157', '简称': '新锦动力'},
 {'代码': '300240', '简称': '飞力达'},
 {'代码': '688010', '简称': '福光股份'},
 {'代码': '300875', '简称': '捷强装备'},
 {'代码': '600798', '简称': '宁波海运'},
 {'代码': '600844', '简称': '丹化科技'},
 {'代码': '600794', '简称': '保税科技'},
 {'代码': '600698', '简称': '湖南天雁'},
 {'代码': '000637', '简称': '茂化实华'},
 {'代码': '601008', '简称': '连云港'},
 {'代码': '002278', '简称': '神开股份'},
 {'代码': '300618', '简称': '寒锐钴业'},
 {'代码': '601022', '简称': '宁波远洋'},
 {'代码': '003026', '简称': '中晶科技'},
 {'代码': '600610', '简称': '中毅达'},
...
 {'代码': '000547', '简称': '航天发展'},
 {'代码': '000881', '简称': '中广核技'},
 {'代码': '600800', '简称': '渤海化学'},
 {'代码': '002109', '简称': '兴化股份'},
 {'代码': '000892', '简称': '欢瑞世纪'}]

第一页的所有股票信息可以成功采集,接下来实现自动翻页采集。

四.翻页采集。

1.动态生成url参数。

每一页的url地址都会发生变化,例如:

第一页的url地址是

"https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/1/free/1/"

第二页的url地址是

 "https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/2/free/1/"

会发现url只有页数的数字改变了。因此需要动态生成url。

page = 2
headers = {
    "User-Agent": "********************************************************************************************************",
    "Accept-Encoding": "gzip, deflate, br",
    }  
url = f"https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/{page}/free/1/"
page_cookie = {
    "v": "A3qivkkdxq0YZUrBCY0TqtC5y6uZK_gvcK5ypoRzJz3anxSVbLtOFUA_wrpX"
}

session = requests.Session()
response = session.get(url = url, headers = headers, cookies = page_cookie, timeout = 10, verify = False)
response.encoding = "gbk"
html = response.text

html_tree = etree.HTML(html)
stock_list = html_tree.xpath("//table[@class='m-table J-ajax-table']/tbody/tr")

结果发现得到的stock_list是空列表:

[]

这是因为当每次刷新页面时浏览器都会自动更新cookie,生成新的cookie,当硬编码cookie时就采集不到数据了,因此要想正确采集,需要做的是通过模拟浏览器的行为来动态生成cookie。

2.动态生成cookie。

需要模拟浏览器动态生成cookie,因此需要知道cookie生成的函数以及位置。

(1).首先我们需要找到cookie生成的程序的位置。点击源代码(第1步),新建一个新片段(第2步),植入hook程序(第3步),并执行程序(第4步)。
在这里插入图片描述
在这里插入图片描述

此时右侧会出现“调用堆栈”,从上往下点,直到找到生成cookie的函数位置。

(2).在本地新建一个js文件,取名“cookie_update_2.js”,然后将chameleon文件里的内容全部复制到“cookie_update_2.js”文件中。

(3).补环境。

document = {
    documentElement:{}
};
window = global;
navigator = {
    plugins:{},
    userAgent:****************************
}
head = {}
div = {}
location = {
    href:'https://data.10jqka.com.cn/market/zdfph/',
    protocol:'https:',
    hostname:'data.10jqka.com.cn',
    host:'data.10jqka.com.cn'
}
Element = {
    protocol:{}
}
null_function = function(){
    console.log(arguments)
}
getElementsByTagName = function(val){
    if(val==="head"){
        return [head]
    }
}
createElement = function(val){
    if(val==="div"){
        return div
    }
}
addEventListener = null_function
window.XMLHttpRequest = null_function
window.ActiveXObject = null_function
navigator.javaEnabled = null_function
document.addEventListener = addEventListener
document.createElement = createElement
document.getElementsByTagName = getElementsByTagName
setInterval = function(){}
var loc_v;

//网站原码
...
//

cookie_v = loc_v()
console.log(cookie_v)

(4).将cookie_update_2.js植入程序,并动态更新cookie。

js_file = open("cookie_update_2.js", encoding = "utf-8").read()
js_code = execjs.compile(js_file)
v = js_code.call("loc_v")
page_cookie = {
    "v":v
}

3.采集数据,并打印结果。

page = 2
js_file = open("cookie_update_2.js", encoding = "utf-8").read()
js_code = execjs.compile(js_file)
v = js_code.call("loc_v")
page_cookie = {
    "v":v
}

headers = {
    "User-Agent": ***********************************************,
    "Accept-Encoding": "gzip, deflate, br",
    }  
url = f"https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/{page}/free/1/"

session = requests.Session()
response = session.get(url = url, headers = headers, cookies = page_cookie, timeout = 10, verify = False)
response.encoding = "gbk"
html = response.text
print(html)
html_tree = etree.HTML(html)
stock_list = html_tree.xpath("//table[@class='m-table J-ajax-table']/tbody/tr")

stocks = []
for stock in stock_list:
    # 从列表中获取第一个元素,如果列表为空则返回None
    code = stock.xpath(".//td[2]/a/text()")
    code = code[0] if code else None
    
    name = stock.xpath(".//td[3]/a/text()")
    name = name[0] if name else None
    # 存储为字典
    stocks.append({
        "代码": code,
        "简称": name
    })    

print(stocks)

打印结果:

[{'代码': '000554', '简称': '泰山石油'},
 {'代码': '600201', '简称': '生物股份'},
 {'代码': '002490', '简称': '山东墨龙'},
 {'代码': '603022', '简称': '新通联'},
 {'代码': '603578', '简称': '三星新材'},
 {'代码': '603928', '简称': '兴业股份'},
 {'代码': '002040', '简称': '南京港'},
 {'代码': '000547', '简称': '航天发展'},
 {'代码': '000881', '简称': '中广核技'},
 {'代码': '600800', '简称': '渤海化学'},
 {'代码': '002753', '简称': '永东股份'},
 {'代码': '002109', '简称': '兴化股份'},
 {'代码': '000892', '简称': '欢瑞世纪'},
 {'代码': '688638', '简称': '誉辰智能'},
 {'代码': '688010', '简称': '福光股份'},
 {'代码': '688230', '简称': '芯导科技'},
 {'代码': '300875', '简称': '捷强装备'},
 {'代码': '000584', '简称': '工智退'},
 {'代码': '688371', '简称': '菲沃泰'},
 {'代码': '300584', '简称': '海辰药业'},
 {'代码': '300541', '简称': '先进数通'},
 {'代码': '300164', '简称': '通源石油'},
 {'代码': '300301', '简称': '*ST长方'},
 {'代码': '301379', '简称': '天山电子'},
 {'代码': '002207', '简称': '准油股份'},
...
 {'代码': '300740', '简称': '水羊股份'},
 {'代码': '600470', '简称': '六国化工'},
 {'代码': '001205', '简称': '盛航股份'},
 {'代码': '601718', '简称': '际华集团'},
 {'代码': '002449', '简称': '国星光电'}]

4.自动翻页采集。

同理,每当翻下一页,cookie都要重新更新。同时加入延时采集,加入异常处理。

pages = 103
headers = {
    "User-Agent": ***************************************,
    "Accept-Encoding": "gzip, deflate, br",
    }  
stocks = []
for page in range(1, pages + 1):
    js_file = open("cookie_update_2.js", encoding = "utf-8").read()
    js_code = execjs.compile(js_file)
    v = js_code.call("loc_v")
    page_cookie = {
        "v":v
    }
    print("正在采集第", page, "页...")
    url = f"https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/{page}/free/1/"
    session = requests.Session()
    for attempt in range(3):
        try:
        # session.get(url = "https://data.10jqka.com.cn/", headers = headers)
            response = session.get(url = url, headers = headers, cookies = page_cookie, timeout = 10, verify = False)
        except TimeoutError as e:
            print(f"第{page}页 请求超时...")
        except ConnectionError as e:
            print(f"第{page}页 连接错误...")
        except ConnectionRefusedError as e:
            print(f"第{page}页 请求异常...")
        except Exception as e:
            print(e)
        else:
            print(f"第{page}页 第{attempt + 1}次获取成功...")
            break
        wait_time = 5 * (2 ** attempt)  # 指数退避策略
        print(f"等待 {wait_time} 秒后重试...")
        time.sleep(wait_time)

    response.encoding = "gbk"
    html = response.text

    html_tree = etree.HTML(html)
    stock_list = html_tree.xpath("//table[@class='m-table J-ajax-table']/tbody/tr")

    for stock in stock_list:
        # 从列表中获取第一个元素,如果列表为空则返回None
        code = stock.xpath(".//td[2]/a/text()")
        code = code[0] if code else None
        
        name = stock.xpath(".//td[3]/a/text()")
        name = name[0] if name else None

        # 存储为字典
        stocks.append({
            "代码": code,
            "简称": name,
        })    
    time.sleep(random.uniform(1, 3))
df_stocks = pd.DataFrame(stocks)

五.对个股详细页面的内容进行采集。

在这里插入图片描述

关于个股的详细信息,例如:所属板块概念、主营业务、上市日期等等并不会展示在股票列表中,需要点进个股页面去采集。

  1. 设置参数。

当点进个股页面以后,复制这一步只需要设置新的url就可以了,cookie可以硬编码。复制搜索框里的地址,动态更新url地址。

code = "000001"
url = f"https://stockpage.10jqka.com.cn/{code}/"

2.采集个股页面中的“涉及概念”。

code = "000001"
headers = {
    "User-Agent": **********************************,
    "Accept-Encoding": "gzip, deflate, br",
    }  
v = "A9wERLvD2L-dXazjU9fdYIKvrfGLVYB_AvmUQ7bd6EeqAXKv3mVQD1IJZNAF"
stock_cookie = {
    "v":v
}
print("正在采集", code, "的概念")
url = f"https://stockpage.10jqka.com.cn/{code}/"
try:
    response = session.get(url = url, headers = headers, cookies = stock_cookie, timeout = 10, verify = False)
except TimeoutError as e:
    print(f"获取{stock} 请求超时...")
except ConnectionError as e:
    print(f"获取{stock} 连接错误...")
except ConnectionRefusedError as e:
    print(f"获取{stock} 请求异常...")
except Exception as e:
    print(e)
response.encoding = "utf-8"
html = response.text

print(html)
<dl class="company_details">
					<!-- <dt>公司名称:</dt>
					<dd>平安银行</dd> -->
					<dt>所属地域:</dt>
					<dd>广东省</dd>
					<dt>涉及概念:</dt>
					<dd title="高股息精选,跨境支付(CIPS),深股通,证金持股,融资融券">高股息精选,跨境支付(CIPS)...</dd>
					<dt>主营业务:</dt>
					<dd><a href="/000001/operate/" target="_blank" class="jyfx stat" stat="f10_spgd_jyfx">经营分析</a></dd>
					<dd title="  办理人民币存、贷、结算、汇兑业务;人民币票据承兑和贴现;各项信托业务;经监管机构批准发行或买卖人民币有价证券;发行金融债券;代理发行、代理兑付、承销政府债券;买卖政府债券;外汇存款、汇款;境内境外借款;从事同业拆借;外汇借款;外汇担保;在境内境外发行或代理发行外币有价证券;买卖或代客买卖外汇及外币有价证券、自营外汇买卖;贸易、非贸易结算;办理国内结算;国际结算;外币票据的承兑和贴现;外汇贷款;资信调查、咨询、见证业务;保险兼业代理业务;代理收付款项;黄金进口业务;提供信用证服务及担保;提供保管箱服务;外币兑换;结汇、售汇;信用卡业务;经有关监管机构批准或允许的其他业务。">办理人民币存、贷、结算、汇兑业务;人民币票据...</dd>
					<dt>上市日期:</dt>
					<dd>1991-04-03</dd>
					<dt>每股净资产:</dt>
					<dd>22.48元</dd>
					<dt>每股收益:</dt>
					<dd>0.62元</dd>
					<dt>净利润:</dt>
					<dd>140.96亿元</dd>
					<dt>净利润增长率:</dt>
					<dd>-5.60%</dd>
					<dt>营业收入:</dt>
					<dd>337.09亿元</dd>
					<dt>每股现金流:</dt>
					<dd>8.40元</dd>
					<dt>每股公积金:</dt>
					<dd>4.16元</dd>
					<dt>每股未分配利润:</dt>
					<dd>13.17元</dd>
					<dt>总股本:</dt>
					<dd>194.06亿</dd>
					<dt>流通股:</dt>
					<dd>194.06亿</dd>
				</dl>

3.解析html。

html_tree = etree.HTML(html)
concept = html_tree.xpath("//dt[text()='涉及概念:']/following-sibling::dd[1]/@title")
print(code, "的概念是:", concept, "\n")

采集成功:

正在采集 000001 的概念
000001 的概念是: ['高股息精选,跨境支付(CIPS),深股通,证金持股,融资融券'] 

六.完整过程。

为了实现自动翻页采集股票列表,并且采集每个股票页面的“所属概念”,只需要将以上过程组合在一起就可以实现了。

pages = 103
headers = {
    "User-Agent": ******************************************,
    "Accept-Encoding": "gzip, deflate, br",
    }  
stocks = []
for page in range(1, pages + 1):
    js_file = open("cookie_update_2.js", encoding = "utf-8").read()
    js_code = execjs.compile(js_file)
    v = js_code.call("loc_v")
    page_cookie = {
        "v":v
    }
    print("正在采集第", page, "页...")
    url = f"https://data.10jqka.com.cn/market/zdfph/field/zdf/order/desc/ajax/1/free/1/page/{page}/free/1/"
    session = requests.Session()
    for attempt in range(3):
        try:
        # session.get(url = "https://data.10jqka.com.cn/", headers = headers)
            response = session.get(url = url, headers = headers, cookies = page_cookie, timeout = 10, verify = False)
        except TimeoutError as e:
            print(f"第{page}页 请求超时...")
        except ConnectionError as e:
            print(f"第{page}页 连接错误...")
        except ConnectionRefusedError as e:
            print(f"第{page}页 请求异常...")
        except Exception as e:
            print(e)
        else:
            print(f"第{page}页 第{attempt + 1}次获取成功...")
            break
        wait_time = 5 * (2 ** attempt)  # 指数退避策略
        print(f"等待 {wait_time} 秒后重试...")
        time.sleep(wait_time)

    response.encoding = "gbk"
    html = response.text

    html_tree = etree.HTML(html)
    stock_list = html_tree.xpath("//table[@class='m-table J-ajax-table']/tbody/tr")

    for stock in stock_list:
        # 从列表中获取第一个元素,如果列表为空则返回None
        code = stock.xpath(".//td[2]/a/text()")
        code = code[0] if code else None
        
        name = stock.xpath(".//td[3]/a/text()")
        name = name[0] if name else None

        # 提取概念
        v = "A9wERLvD2L-dXazjU9fdYIKvrfGLVYB_AvmUQ7bd6EeqAXKv3mVQD1IJZNAF"
        stock_cookie = {
            "v":v
        }
        print("正在采集", name, "的概念")
        url = f"https://stockpage.10jqka.com.cn/{code}/"
        # session = requests.Session()
        # session.get(url = "https://data.10jqka.com.cn/", headers = headers)
        try:
            response = session.get(url = url, headers = headers, cookies = stock_cookie, timeout = 10, verify = False)
        except TimeoutError as e:
            print(f"获取{stock} 请求超时...")
        except ConnectionError as e:
            print(f"获取{stock} 连接错误...")
        except ConnectionRefusedError as e:
            print(f"获取{stock} 请求异常...")
        except Exception as e:
            print(e)
        response.encoding = "utf-8"
        html = response.text

        html_tree = etree.HTML(html)
        concept = html_tree.xpath("//dt[text()='涉及概念:']/following-sibling::dd[1]/@title")
        print(name, "的概念是:", concept, "\n")
                    

        # 存储为字典
        stocks.append({
            "代码": code,
            "简称": name,
            "涉及概念": concept
        })    
    time.sleep(random.uniform(1, 3))
df_stocks = pd.DataFrame(stocks)

执行结果:

正在采集第 1...1页 第1次获取成功...
正在采集 新恒汇 的概念

新恒汇 的概念是: ['融资融券,注册制次新股,新股与次新股,人工智能,物联网,专精特新,芯片概念'] 

正在采集 华之杰 的概念
华之杰 的概念是: ['融资融券,注册制次新股,新股与次新股,消费电子概念,人民币贬值受益'] 

正在采集 深水规院 的概念
深水规院 的概念是: ['抽水蓄能,物业管理,物联网,数字孪生,华为概念,PPP概念,智慧政务,乡村振兴,国企改革,新型城镇化,地下管网,污水处理,融资融券,粤港澳大湾区,水利,深圳国企改革'] 

正在采集 强力新材 的概念
强力新材 的概念是: ['PCB概念,芯片概念,先进封装,专精特新,富媒体,融资融券,光刻胶,深股通,OLED'] ...
...

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐