准备

安装postgreSQL数据库,和可视化工具pgadmin3,或者其他数据库

实现功能,抓取12306全部的站点,并实现通过站点查询出所有经过次站点的车次,通过车次查出次列车经过的城市

分析

分析12306,找合适的接口,最符合要求的是查询车次的这张页面,但是有验证码,无形增加了难度

经过分析,合适的页面是车票预订的页面,查询两个站点直接的车次,用火狐自带的f12工具,点击查询清晰的看到只有一条get请求

再看响应的内容,json,根据经验这是我们想要东西

通过这条链接,我们可以得到两站点之间的车次信息,我们只需要车次的名称就好了,通过字符串或者正则都可以,正则不太熟,我用的是字符串

分析怎么才能把全国的站点和车次都抓取到,并且实现彼此查询的功能?

站点和城市多对多关系,理应建立三张表,用中间表关联.最后放弃了三表的想法,使用一张表联合主键实现

只要获取到全国的城市站点,通过for循环两两测试,不就可以得到全部的火车车次了,并且两列都是主键,同时还解决了两个城市之间车次重复的问题,

1 CREATE TABLE public.t_city2(3 city_name character varying(64) NOT NULL,4 train_num character varying(64) NOT NULL,5CONSTRAINT t_city_pkey PRIMARY KEY (city_name, train_num)6 )

下一步要找到全国的火车站点

从页面的一条js中,找到一条连接 https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9049

一条json数据

接下来,开始写程序,解析数据

数据库链接(换了台电脑改成了mysql数据库

publicclass DbUtil {

private static final String DBDRIVER="com.mysql.jdbc.Driver";

private static final String url= "jdbc:mysql://127.0.0.1:3306/lianxi";

private static final StringUSER ="root";

private static final String PASSWORD= "123";publicConnection getConn() throws ClassNotFoundException, SQLException {

Class.forName(DBDRIVER);

Connection conn= DriverManager.getConnection(url, USER, PASSWORD);returnconn;

}publicvoid closeConn(Connection conn) throws SQLException {if (conn != null) {

conn.close();

}

}public static void main(String args[]) {

DbUtil dbUtil=new DbUtil();

Connection conn=null;

try {

conn=dbUtil.getConn();

System.out.println(conn+"数据库连接成功");

} catch (ClassNotFoundException|SQLException e) {

e.printStackTrace();

System.out.println("失败");

}finally {

try {

dbUtil.closeConn(conn);

} catch (SQLException e) {// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

数据库用sqlyog直接建好表

创建一个CityMd类

public classCityMd {privateString cityName;privateString trainName

、、、、、、

创建方法,实现数据库数据添加

public classDbChange {public intadd(Connection conn,CityMd cityMd) {

String sql="insert into t_city values(?,?,null)";int n=0;try{

PreparedStatement p=conn.prepareStatement(sql);

p.setString(1, cityMd.getCityName());

p.setString(2, cityMd.getTrainName());

n=p.executeUpdate();

p.close();

}catch(SQLException e) {//TODO Auto-generated catch block//e.printStackTrace();

}finally{try{

conn.close();

}catch(SQLException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}returnn;

}

}

抓取全部的站点,返回一个二维数组,通过之前的url,发现参数有出发地和目的地,并且是字母编号的形式,所以把城市和编号同时抓取下来

分析json数据,每个成熟以@分隔,其次又以|分隔,所以可以用字符串分隔,正则很方便,不过熟悉没用

public classCityUtil {public String[][] getCity() throwsException{String cityurl="https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9048";

HttpGet httpget=newHttpGet(cityurl);

CloseableHttpClient httPclient=HttpClients.createDefault();

CloseableHttpResponse Response=httPclient.execute(httpget);

HttpEntity entity=Response.getEntity();

String result=EntityUtils.toString(entity,"utf-8");//System.out.println("请求结果"+result);

int l1=result.indexOf("'");int l2=result.length();

String city=result.substring(l1+1, l2);

String[] c=city.split("@");//导入二维数组

int l=c.length-1;

String[][] str=new String[l][2];for(int i=1;i

String[] cc=c[i].split("[|]");//System.out.println(cc[1]+" "+cc[2]);

str[i-1][0]=cc[1];

str[i-1][1]=cc[2];

}

returnstr;

}

}

这样就得到了一个全部站点的数组

接下来写两地间车次的方法,两地之间肯定会有很多火车,所以返回数组

public classGetUtil {publicString[] getList(String url) {

CloseableHttpClient httPclient=HttpClients.createDefault();

HttpGet httpgett=newHttpGet(url);CloseableHttpResponse Response;

String result1=null;try{

Response=httPclient.execute(httpgett);

HttpEntity entity=Response.getEntity();

result1=EntityUtils.toString(entity,"utf-8");//System.out.println("请求结果"+result1);

} catch(ClientProtocolException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IOException e) {//TODO Auto-generated catch block

e.printStackTrace();

}JSONObject jSONObject=JSONObject.fromObject(result1);

Object listObject=jSONObject.get("data");

jSONObject=JSONObject.fromObject(listObject);

JSONArray json=jSONObject.getJSONArray("result");//存放火车列次的数组

String[] strs=newString[json.size()];for (int i = 0; i < json.size(); i++) {

String str=json.getString(i);

String[] arr=str.split("[|]");

strs[i]=arr[3];

}

returnstrs;

}

}

剩下的就是,整合起来,开始测试

get请求的url参数有四个,第一个是时间,第二个是出发点,第三个是目的地,最后一个成人票这个不是关键直接写死

时间也写死,但是有一个问题就是,每天的车次肯定会有差异,这样只看一看的车次数据肯定不精准。想一个办法就是,跑完数据之后,换个时间再抓一次,反正重复的自己会跳过去、、、、、、、

一定注意要加时间间隔,开始跑没有加,没一会12306就给限制请求了

GetUtil getUtil=new GetUtil(); //两地之间的车次

DbUtil dbUtil=new DbUtil(); //获取conn

Zhuanhua zh=new Zhuanhua(); //集合转数组

String trainurl="https://kyfw.12306.cn/otn/leftTicket/queryO?";

String train_date="leftTicketDTO.train_date=2018-03-20";

String from_station=null;

String to_station=null;

String newurl=null;//获取conn//Connection conn=dbUtil.getConn();

DbChange db=newDbChange();//获取全部城市和它代号

CityUtil cu=newCityUtil();

String[][] str=cu.getCity();//循环所有情况

int count=0;

Connection conn=null;for(int i=10; i

Thread.sleep(1000);for(int j=0; j

Random r= newRandom();int nnn=r.nextInt(6);

Thread.sleep(nnn*2000);//拼接链接请求链接

from_station=str[i][1];

to_station=str[j][1];//排除出发和目的是一个

if(from_station.equals(to_station)) {continue;

}

newurl=trainurl+train_date+"&leftTicketDTO.from_station="

+from_station+"&leftTicketDTO.to_station="+to_station+"&purpose_codes=ADULT";//调用方法,获取两地之间的火车数组

String[] ss=getUtil.getList(newurl);for(int k=0;k

CityMd cityMd=new CityMd(str[i][0],ss[k]);

conn=dbUtil.getConn();int nn=db.add(conn, cityMd);

System.out.println("运行第"+k+"次出发地:"+str[i][0]+"==>目的地:"+str[j][0]);

count+=nn;

}

}

} System.out.println("共计导入数据"+count);

最终数据库实现

java爬虫12306_java爬虫12306,爬取所有的站点和车次,并导入postgreSQL数据库相关推荐

  1. mysql 轨迹数据存储_python爬虫26 | 把数据爬取下来之后就存储到你的MySQL数据库...

    小帅b说过 在这几篇中会着重说说将爬取下来的数据进行存储 上次我们说了一种 csv 的存储方式 这次主要来说说怎么将爬取下来的数据保存到 MySQL 数据库 接下来就是 学习python的正确姿势 真 ...

  2. 爬虫介绍02:爬取第一个站点

    为了搜刮某个站点,第一步我们需要下载该站包含有用信息的页面,也就是我么尝尝提到的爬取过程.爬站的方式多种多样,我们需要根据目标站点的结构选择合适的爬站方案.下面讨论如何安全的爬站,以及常用的三种方法: ...

  3. java爬虫的2种爬取方式(HTTP||Socket)简单Demo(一)

    转载自 java爬虫的2种爬取方式(HTTP||Socket)简单Demo(一) 最近在找java的小项目自己写着玩,但是找不到合适的,于是写开始学一点爬虫,自己也是感觉爬虫比较有趣.这里自己找了一个 ...

  4. 教你如何使用Java代码从网页中爬取数据到数据库中——网络爬虫精华篇

    文章目录 1:网络爬虫介绍 2:HttpClients类介绍 2.1 HttpGet参数问题 2.2 HttpPost参数问题 2.3 连接池技术问题 3:Jsoup介绍 4:动手实践如何抓取网页上数 ...

  5. python爬虫从入门到实战笔记——第一章爬虫原理和数据爬取

    爬虫原理和数据抓取 1.1 通用爬虫和聚焦爬虫 通用爬虫 聚焦爬虫 1.2 HTTP和HTTPS HTTP的请求与响应 浏览器发送HTTP请求的过程: 客户端HTTP请求 请求方法 常用的请求报头 服 ...

  6. perl脚本爬虫程序,支持爬取北大未名bbs、163新闻、ifeng新闻、猫扑论坛、sina新闻等

    [实例简介] 采用perl脚本写的爬虫程序,可以爬取北大未名bbs.163新闻.ifeng新闻.猫扑论坛.sina新闻等 [实例截图] 文件:590m.com/f/25127180-494436243 ...

  7. python中爬虫程序提问,python爬虫(二)爬取知乎问答

    都说知乎上问答的质量挺高,刚学爬虫没几天,现在对其问答内容进行爬虫实验. 在知乎首页,通过输入关键词,搜索问题,之后点击问题找到该问题对应的网友回答. 根据该过程,爬虫过程需要分为两步: 1.通过关键 ...

  8. python爬取图片教程-推荐|Python 爬虫系列教程一爬取批量百度图片

    Python 爬虫系列教程一爬取批量百度图片https://blog.csdn.net/qq_40774175/article/details/81273198# -*- coding: utf-8 ...

  9. Scrapy爬虫(6)爬取银行理财产品并存入MongoDB(共12w+数据)

      本次Scrapy爬虫的目标是爬取"融360"网站上所有银行理财产品的信息,并存入MongoDB中.网页的截图如下,全部数据共12多万条.   我们不再过多介绍Scrapy的创建 ...

  10. 爬虫篇——代理IP爬取备用及存储

    爬虫篇--代理IP爬取备用及存储 代码 代码 本文通过抓取免费的高匿IP代理,将其写入列表并保存为json格式文件,且将代码进行了封装,方便以后抓取数据时动态的更新handle的IP地址,从一方面避免 ...

最新文章

  1. AAAI | 深度生成模型—NEVAE
  2. 5G+AI成产业新引擎 安防行业切入点在哪里?
  3. Apache 'mod_accounting'模块SQL注入漏洞(CVE-2013-5697)
  4. c#中的interface abstract 与 virtual(转)
  5. 1.2 实例:封装图书信息类
  6. 09_分类算法--k近邻算法(KNN)、案例、欧氏距离、k-近邻算法API、KNeighborsClassifier、及其里面的案例(网络资料+学习资料整理笔记)
  7. 前端 html border-right: 1px solid red;
  8. 异步IO\数据库\队列\缓存
  9. ubuntu安装VMware出错
  10. synchronized的实现原理
  11. 定期清理sql2005事务日志
  12. The current branch is not configured for pull N...
  13. vue2.0:(六)、移动端像素border的实现和整合引入less文件
  14. c 提示错误expected) before ; token_NLP.TM[33] | 纠错:pycorrector的错误检测
  15. Java——异常和断言
  16. vim 对齐插件Tabular使用
  17. 逍遥模拟器安装xposed installer
  18. 为什么要做小程序?90%的商家不知道的好处!
  19. 小妙招,教你从旅行网上下载各种美图和视频!
  20. Android 短视频编辑开发之摄像头预览实时美颜(三)

热门文章

  1. 10 个最佳 GIS 软件应用程序
  2. 重启路由器可以换IP吗
  3. 数据分析与可视化概述
  4. quartus II 13.1 软件破解
  5. Java程序员怎么优雅迈过30K+这道坎?附超全教程文档
  6. 7天连锁酒店郑南雁:顺势创业者无为管理人
  7. Centos6.5 一件安装FFmpeg 包括其中的坑
  8. 一图看懂什么是集成电路?
  9. 如何枚举系统的视音频采集设备
  10. Delphi 2009 安装序列号