python爬取同花顺_Java爬取同花顺股票数据(附源码)

最近有小伙伴问我能不能抓取同花顺的数据,最近股票行情还不错,想把数据抓下来自己分析分析。我大A股,大家都知道的,一个概念火了,相应的股票就都大涨。

如果能及时获取股票涨跌信息,那就能在刚开始火起来的时候杀进去,小赚一笔。但是股票那么多,小伙伴也盯不过来,于是就微信问我,能不能抓取同花顺的板块下的股票信息存到数据库里?他就能根据数据库里的数据,制定一些策略。

俗话说:哪里有痛点,哪里就有编程!不就是个同花顺嘛,办他!

调研背景

于是我点开了同花顺的板块页面:http://q.10jqka.com.cn/gn/ 发现有好268个概念:

分析概念板块的网页HTML发现,268个概念的URL就在HTML中:

打开其中的“阿里巴巴概念”,发现网页又有分页:

分页的数据,是根据接口实时获取的,接口中注入了一些Cooki信息和其他标识,同花顺的反爬虫策略一直比较强,使用模拟接口的方式可能难度会比较大,所以使用selenium模拟浏览器操作这种方式比较完美。

设计方案

技术方向有了,再简单整理一下思路:根据http://q.10jqka.com.cn/gn/,获取板块网页的源码HTML,用Jsoup解析HTML获取每个概念的url信息放到List中

遍历List,根据概念的url获取概念网页源码HTML,解析股票信息

再递归点击执行“下一页”操作,获取每一页的股票数据,直至尾页

把股票信息存储到数据库

配置环境

先介绍下工程所需要的环境:编码工具:idea 语言:java 依赖:jdk1.8、maven、chrome、ChromeDriver

我们使用的方案是模拟浏览器的操作,所以我们需要在电脑安装chrome浏览器和chromedriver驱动。chrome的安装这里就不说了,百度下载个浏览器就行。

关键是安装 ChromeDriver ,需要安装和当前chrome版本一致的驱动才写。

查看chrome版本:chrome浏览器输入:Chrome://version

在根据版本下载对于的驱动,版本最好要一致,比如我的是:79.0.3945.117 (正式版本) (64 位),我下载的就是 79.0.3945.36。

ChromeDriver各版本的下载地址:

下面这一步可做可不做,不做也能启动工程,只是需要修改代码中的一个配置即可。配置方式:

将下载好的ChromeDriver文件放到/usr/local/bin/目录下:

shell cp chromedriver /usr/local/bin/

检测是否安装成功

shell chromedriver --version

如果不配置,只需要记得修改ChromeDriver在代码中配置的路径,你只需要将路径改为你自己的ChromeDriver路径即可,比如我的是:

System.setProperty(

"webdriver.chrome.driver",

"/Users/admin/Documents/selenium/chrome/79.0.3945.36/chromedriver"

);

记得修改代码里ChromeDriver的路径。 记得修改代码里ChromeDriver的路径。 记得修改代码里ChromeDriver的路径。

验证方案

首先完成设计方案中的三步

package com.ths.controller;

import com.ths.service.ThsGnCrawlService;

import com.ths.service.ThsGnDetailCrawlService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;

import java.util.List;

@Controller

public class CrawlController {

@Autowired

private ThsGnCrawlService thsGnCrawlService;

@Autowired

private ThsGnDetailCrawlService thsGnDetailCrawlService;

@RequestMapping("/test")

@ResponseBody

public void test() {

// 抓取所有概念板块的url List> list = thsGnCrawlService.ThsGnCrawlListUrl();

// 放入阻塞队列 thsGnDetailCrawlService.putAllArrayBlockingQueue(list);

// 根据url多线程抓取 thsGnDetailCrawlService.ConsumeCrawlerGnDetailData(1);

}

}

先看看thsGnCrawlService.ThsGnCrawlListUrl();方法,如何抓取所有概念板块的url?

package com.ths.service.impl;

import com.ths.parse.service.ThsParseHtmlService;

import com.ths.service.ThsGnCrawlService;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.chrome.ChromeOptions;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.HashMap;

import java.util.List;

import java.util.concurrent.TimeUnit;

@Service

public class ThsGnCrawlServiceImpl implements ThsGnCrawlService {

private final static Logger LOGGER = LoggerFactory.getLogger(ThsGnCrawlServiceImpl.class);

/*** 同花顺全部概念板块url*/

private final static String GN_URL = "http://q.10jqka.com.cn/gn/";

@Autowired

private ThsParseHtmlService thsParseHtmlService;

@Override

public List> ThsGnCrawlListUrl() {

System.setProperty("webdriver.chrome.driver", "/Users/admin/Documents/selenium/chrome/79.0.3945.36/chromedriver");

ChromeOptions options = new ChromeOptions();

//是否启用浏览器界面的参数 //无界面参数// options.addArguments("headless"); //禁用沙盒 就是被这个参数搞了一天// options.addArguments("no-sandbox"); WebDriver webDriver = new ChromeDriver(options);

try {

// 根据网速设置,网速慢可以调低点 webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);

webDriver.get(GN_URL);

Thread.sleep(1000L);

String gnWindow = webDriver.getWindowHandle();

// 获取同花顺概念页面的HTML String thsGnHtml = webDriver.getPageSource();

LOGGER.info("获取同花顺url:[{}]的html为:/n{}", GN_URL, thsGnHtml);

return thsParseHtmlService.parseGnHtmlReturnGnUrlList(thsGnHtml);

} catch (Exception e) {

LOGGER.error("获取同花顺概念页面的HTML,出现异常:", e);

} finally {

webDriver.close();

webDriver.quit();

}

return null;

}

}

这里使用了上文说的ChromeDriver,我们需要根据自己的配置,修改对应的地址(重复第四遍!)。 根据代码可以看到String thsGnHtml = webDriver.getPageSource();方法获取页面的HTML,再解析HTML就能获取各大概念板块的url。

解析HTML我使用的是Jsoup,简单易上手,api也很简单,解析HTML获取各大板块的url的代码如下:

package com.ths.parse.service.impl;

import com.ths.parse.service.ThsParseHtmlService;

import org.jsoup.Jsoup;

import org.jsoup.helper.StringUtil;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

import org.springframework.stereotype.Service;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

@Service

public class ThsParseHtmlServiceImpl implements ThsParseHtmlService {

/*** 解析同花顺概念板块的Html页面:http://q.10jqka.com.cn/gn/* 返回所有概念板块的url地址*/

public List> parseGnHtmlReturnGnUrlList(String html) {

if (StringUtil.isBlank(html)) {

return null;

}

List> list = new ArrayList<>();

Document document = Jsoup.parse(html);

Elements cateItemsFromClass = document.getElementsByClass("cate_items");

for (Element element : cateItemsFromClass) {

Elements as = element.getElementsByTag("a");

for (Element a : as) {

String gnUrl = a.attr("href");

String name = a.text();

HashMap map = new HashMap<>();

map.put("url", gnUrl);

map.put("gnName", name);

list.add(map);

}

}

return list;

}

}

可以看到,只要在html中有的数据,定位到标签就能获取对应的数据。

然后放到阻塞队列:

/*** 阻塞队列*/

private ArrayBlockingQueue> arrayBlockingQueue = new ArrayBlockingQueue<>(1000);

@Override

public void putAllArrayBlockingQueue(List> list) {

if (!CollectionUtils.isEmpty(list)) {

arrayBlockingQueue.addAll(list);

}

}

再开启多个线程,从阻塞队列里获取url,分别抓取概念板块的股票数据,如果页面有分页,就循环点击下一页,再获取数据,直到尾页,代码如下:

package com.ths.service.impl;

import com.ths.dao.StockThsGnInfoDao;

import com.ths.domain.StockThsGnInfo;

import com.ths.service.ThsGnDetailCrawlService;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.chrome.ChromeOptions;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.util.CollectionUtils;

import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;

import java.math.BigDecimal;

import java.text.SimpleDateFormat;

import java.util.*;

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.TimeUnit;

@Service

public class ThsGnDetailCrawlServiceImpl implements ThsGnDetailCrawlService {

private final static Logger LOGGER = LoggerFactory.getLogger(ThsGnDetailCrawlServiceImpl.class);

/*** 阻塞队列*/

private ArrayBlockingQueue> arrayBlockingQueue = new ArrayBlockingQueue<>(1000);

@Autowired

private StockThsGnInfoDao stockThsGnInfoDao;

@Override

public void putAllArrayBlockingQueue(List> list) {

if (!CollectionUtils.isEmpty(list)) {

arrayBlockingQueue.addAll(list);

}

}

@Override

public void ConsumeCrawlerGnDetailData(int threadNumber) {

for (int i = 0; i < threadNumber; ++i) {

LOGGER.info("开启线程第[{}]个消费", i);

new Thread(new crawlerGnDataThread()).start();

}

LOGGER.info("一共开启线程[{}]个消费", threadNumber);

}

class crawlerGnDataThread implements Runnable {

@Override

public void run() {

try {

while (true) {

Map map = arrayBlockingQueue.take();

String url = map.get("url");

String gnName = map.get("gnName");

String crawlerDateStr = new SimpleDateFormat("yyyy-MM-dd HH:00:00").format(new Date());

//chromederiver存放位置 System.setProperty("webdriver.chrome.driver", "/Users/admin/Documents/selenium/chrome/79.0.3945.36/chromedriver");

ChromeOptions options = new ChromeOptions();

//无界面参数 // options.addArguments("headless"); //禁用沙盒 就是被这个参数搞了一天 // options.addArguments("no-sandbox"); WebDriver webDriver = new ChromeDriver(options);

try {

webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);

webDriver.get(url);

Thread.sleep(1000L);

String oneGnHtml = webDriver.getPageSource();

LOGGER.info("当前概念:[{}],html数据为[{}]", gnName, oneGnHtml);

LOGGER.info(oneGnHtml);

// TODO 解析并存储数据 parseHtmlAndInsertData(oneGnHtml, gnName, crawlerDateStr);

clicktoOneGnNextPage(webDriver, oneGnHtml, gnName, crawlerDateStr);

} catch (Exception e) {

LOGGER.error("用chromerDriver抓取数据,出现异常,url为[{}],异常为[{}]", url, e);

} finally {

webDriver.close();

webDriver.quit();

}

}

} catch (Exception e) {

LOGGER.error("阻塞队列出现循环出现异常:", e);

}

}

}

public void parseHtmlAndInsertData(String html, String gnName, String crawlerDateStr) {

Document document = Jsoup.parse(html);

// Element boardElement = document.getElementsByClass("board-hq").get(0);// String gnCode = boardElement.getElementsByTag("h3").get(0).getElementsByTag("span").get(0).text();

Element table = document.getElementsByClass("m-pager-table").get(0);

Element tBody = table.getElementsByTag("tbody").get(0);

Elements trs = tBody.getElementsByTag("tr");

for (Element tr : trs) {

try {

Elements tds = tr.getElementsByTag("td");

String stockCode = tds.get(1).text();

String stockName = tds.get(2).text();

BigDecimal stockPrice = parseValueToBigDecimal(tds.get(3).text());

BigDecimal stockChange = parseValueToBigDecimal(tds.get(4).text());

BigDecimal stockChangePrice = parseValueToBigDecimal(tds.get(5).text());

BigDecimal stockChangeSpeed = parseValueToBigDecimal(tds.get(6).text());

BigDecimal stockHandoverScale = parseValueToBigDecimal(tds.get(7).text());

BigDecimal stockLiangBi = parseValueToBigDecimal(tds.get(8).text());

BigDecimal stockAmplitude = parseValueToBigDecimal(tds.get(9).text());

BigDecimal stockDealAmount = parseValueToBigDecimal(tds.get(10).text());

BigDecimal stockFlowStockNumber = parseValueToBigDecimal(tds.get(11).text());

BigDecimal stockFlowMakertValue = parseValueToBigDecimal(tds.get(12).text());

BigDecimal stockMarketTtm = parseValueToBigDecimal(tds.get(13).text());

// 存储数据 StockThsGnInfo stockThsGnInfo = new StockThsGnInfo();

stockThsGnInfo.setGnName(gnName);

stockThsGnInfo.setGnCode(null);

stockThsGnInfo.setStockCode(stockCode);

stockThsGnInfo.setStockName(stockName);

stockThsGnInfo.setStockPrice(stockPrice);

stockThsGnInfo.setStockChange(stockChange);

stockThsGnInfo.setStockChangePrice(stockChangePrice);

stockThsGnInfo.setStockChangeSpeed(stockChangeSpeed);

stockThsGnInfo.setStockHandoverScale(stockHandoverScale);

stockThsGnInfo.setStockLiangBi(stockLiangBi);

stockThsGnInfo.setStockAmplitude(stockAmplitude);

stockThsGnInfo.setStockDealAmount(stockDealAmount);

stockThsGnInfo.setStockFlowStockNumber(stockFlowStockNumber);

stockThsGnInfo.setStockFlowMakertValue(stockFlowMakertValue);

stockThsGnInfo.setStockMarketTtm(stockMarketTtm);

stockThsGnInfo.setCrawlerTime(crawlerDateStr);

stockThsGnInfo.setCrawlerVersion("同花顺概念板块#" + crawlerDateStr);

stockThsGnInfo.setCreateTime(new Date());

stockThsGnInfo.setUpdateTime(new Date());

stockThsGnInfoDao.insert(stockThsGnInfo);

} catch (Exception e) {

LOGGER.error("插入同花顺概念板块数据出现异常:", e);

}

}

}

public BigDecimal parseValueToBigDecimal(String value) {

if (StringUtils.isEmpty(value)) {

return BigDecimal.ZERO;

} else if ("--".equals(value)) {

return BigDecimal.ZERO;

} else if (value.endsWith("亿")) {

return new BigDecimal(value.substring(0, value.length() - 1)).multiply(BigDecimal.ONE);

}

return new BigDecimal(value);

}

public boolean clicktoOneGnNextPage(WebDriver webDriver, String oneGnHtml, String key, String crawlerDateStr) throws InterruptedException {

// 是否包含下一页 String pageNumber = includeNextPage(oneGnHtml);

if (!StringUtils.isEmpty(pageNumber)) {

WebElement nextPageElement = webDriver.findElement(By.linkText("下一页"));

webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);

nextPageElement.click();

Thread.sleep(700);

String nextPageHtml = webDriver.getPageSource();

LOGGER.info("下一页:");

LOGGER.info(nextPageHtml);

// TODO 解析并存储数据 parseHtmlAndInsertData(nextPageHtml, key, crawlerDateStr);

clicktoOneGnNextPage(webDriver, nextPageHtml, key, crawlerDateStr);

}

return true;

}

public String includeNextPage(String html) {

Document document = Jsoup.parse(html);

List list = document.getElementsByTag("a");

for (Element element : list) {

String a = element.text();

if ("下一页".equals(a)) {

String pageNumber = element.attr("page");

return pageNumber;

}

}

return null;

}

}

最后对,概念板块的页面数据进行解析入库。

数据展示

如果遇到问题,可以关注我的公众号:java之旅或扫描下方二维码,回复【加群】,加我个人微信询问我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开会=浪费时间?阿里技术团队这样开项目复盘会

2019独角兽企业重金招聘Python工程师标准>>> 阿里妹导读&#xff1a;复盘是项目结束后必不可少的阶段&#xff0c;好的复盘会议能够有效地促进团队成长。今天&#xff0c;阿里项目管理专家鹿迦以自身的经验&#xff0c;为大家分享如何做好一个项目的复盘。这篇文章分…

Spring @Value注解无法正确赋值问题

正确的调用方式为&#xff1a; Component public class IconProperties {Value("${icon.url}")private String url; } public class test{AutowiredIconProperties icon;public void test(){ String url icon.url; } } 这里有三个需要注意的点&#xff1a; 1.Value…

Extjs中使用FusionChart举例

一 前言&#xff1a; 在项目实施中&#xff0c;设计统计部分经常会使用图表进行显示&#xff0c;在Extjs3中内置了图表控件&#xff0c;但实际表现无法达到3D的美观效果&#xff0c;通过查找FusionChart可以实现比较美观的3D或2D图表显示。注&#xff1a;FusionChart是个商业…

drawitem设置指定行的背景颜色_Java 为 Excel 中的行设置交替背景色

点击上方 好好学java &#xff0c;选择 星标 公众号重磅资讯、干货&#xff0c;第一时间送达今日推荐&#xff1a;牛人 20000 字的 Spring Cloud 总结&#xff0c;太硬核了~作者&#xff1a;Jazzz链接&#xff1a;https://www.cnblogs.com/jazz-z/p/12665819.html在制作Excel表…

常见的关系型数据库和非关系型数据及其区别

一、关系型数据库 关系型数据库最典型的数据结构是表&#xff0c;由二维表及其之间的联系所组成的一个数据组织 优点&#xff1a;1、易于维护&#xff1a;都是使用表结构&#xff0c;格式一致&#xff1b;2、使用方便&#xff1a;SQL语言通用&#xff0c;可用于复杂查询&#x…

逆序数技巧 - 牛客

链接&#xff1a;https://ac.nowcoder.com/acm/contest/308/D来源&#xff1a;牛客网 题目描述 tokitsukaze给你一个长度为n的序列&#xff0c;这个序列是1到n的一种排列。然后她会进行q次操作。每次操作会给你L R k这三个数&#xff0c;表示区间[L,R]往右移动k次。移动一次的…

Ajax跨域提交JSON和JSONP

可以直接使用$.getJSON()方法实现跨域请求&#xff0c;参数中必须加上callback&#xff0c;如&#xff1a; var jsonpUrl http://www.test.com/index.php?cApi_Order&aAddOrder&callback?;var param {uid:uid,type:type,cityId:cityId};$.getJSON(jsonpUrl, param,…

mysql数据库商业版与社区版的区别

1、商业版本组织管理与测试环节控制更严格&#xff0c;稳定性方面&#xff0c;会比社区版本更稳定。 2、mysql是成熟产品&#xff0c;商业版与社区版之间性能方面相差不大。 3、商业版不遵守GPL协议&#xff0c;社区版遵守GPL协议可以免费使用。 4、使用商业版后可以购买相关的…

UML的奥妙 - 学习UML笔记(1)

前两天买了一本《大象 Thinking in UML》&#xff0c;其实本就有学习UML的念头&#xff0c;但都因这样那样的事儿耽搁了&#xff0c;当然&#xff0c;也有些惰性在作祟...... 闲话少说&#xff0c;这本书看完了一章&#xff0c;发现还是不错的&#xff0c;先把这两天的学习情况…

无法检查指定的位置是否位于cfs上_(干货分享)一文搞明白 节气门位置传感器的作用、故障类型与症状、诊断方法...

1 位置节气门位置传感器(ThrottlePositionSensor&#xff0c;TPS)&#xff0c;位于节气门体上&#xff0c;其安装形式因节气门结构的不同而有所差异&#xff1a;对于传统的机械拉索式节气门&#xff0c;节气门位置传感器通常以一个独立元件的形式安装在节气门体的侧面&#xf…

盒子模型

1 <!doctype html>2 <html>3 <head>4 <title>盒子模型</title>5 <meta charset"utf-8">6 <meta name"keywords", content"">7 <meta name"description&…

表单跨域提交

利用form表单跨域post 现在ajax应用这么广泛&#xff0c;一般的应用都是直接通过异步调用就可以了&#xff0c;但是有些东西必须要使用post&#xff0c;而且是跨域的时候&#xff0c;ajax异步调用的方式就无能为力了。当然现在也有很多种办法&#xff0c;比如通过flash中转去po…

Asp.net(C#)-显示所有缓存 清除所有缓存

//清除所有缓存protectedvoidRemoveAllCache() { System.Web.Caching.Cache _cache HttpRuntime.Cache; IDictionaryEnumerator CacheEnum _cache.GetEnumerator(); ArrayList al new ArrayList(); while (CacheEnum.MoveNext()) { …

mysql数据库三大引擎优缺点

1.MyISAM 特性&#xff1a; ①不支持事务。 ②表级锁定&#xff0c;并发性能大大降低。 ③读写互相阻塞。 适用场景&#xff1a; ①不支持事务。 ②并发相对较低&#xff0c;表锁定。 ③执行大量select语句操作的表。 ④count(*)操作较快。 ⑤不支持外键。 注&#xff1a;查询速…

Python--day60--一个简单(不完整)的web框架

转载于:https://www.cnblogs.com/xudj/p/10091775.html

activemq 发两条只收到一条_浅谈ActiveMQ与使用

更多大数据架构、实战经验&#xff0c;欢迎关注【大数据每日哔哔】&#xff0c;期待与你一起成长&#xff01;本文将介绍一下 ActiveMQ 的安装、原理和简单实战。一、什么是消息中间件消息中间件顾名思义实现的就是在两个系统或两个客户端之间进行消息传送二、什么是ActiveMQAc…

php发送get、post请求的几种方法

方法1: 用file_get_contents 以get方式获取内容 <?php $urlhttp://www.domain.com/; $html file_get_contents($url); echo $html; ?>方法2: 用fopen打开url, 以get方式获取内容<?php $fp fopen($url, r); stream_get_meta_data($fp); while(!feof($fp)) { $res…

ZZ:深入理解new

new的过程当我们使用关键字new在堆上动态创建一个对象时&#xff0c;它实际上做了三件事&#xff1a;获得一块内存空间、调用构造函数、返回正确的指针。当然&#xff0c;如果我们创建的是简单类型的变量&#xff0c;那么第二步会被省略。假如我们定义了如下一个类A&#xff1a…

mysql数据库的优缺点

优点1. 通常存储过程 标题有助于提高应用程序的性能。因为当你创建他的时候就已经编译了&#xff0c;只不过是按需编译的。2.存储过程有助于减少应用程序和数据库服务器之间的流量&#xff0c;因为应用程序不必发送多个冗长的SQL语句&#xff0c;而只能发送存储过程的名称和参数…

大数据小白系列——HDFS(1)

【注1&#xff1a;结尾有大福利&#xff01;】 【注2&#xff1a;想写一个大数据小白系列&#xff0c;介绍大数据生态系统中的主要成员&#xff0c;理解其原理&#xff0c;明白其用途&#xff0c;万一有用呢&#xff0c;对不对。】 大数据是什么&#xff1f;抛开那些高大上但笼…