简单易懂的java爬虫--抓取携程上的酒店信息

    手上的项目有个业务要求:采集某市的酒店余房情况,淡季一天更新一次,旅游高峰期半小时更新一次。

    正常情况是要有个接口,酒店相关人员负责定时发送酒店余房情况,但这时候我觉得,可以用爬虫玩玩,反正也不会爬虫,学下爬虫也不亏,项目是用java语言SSM框架写的,所以想尝试用java语言。

    上网了解了一下,java基础爬虫语法很简单。

//首先输入要爬的网页
URL url = new URL("https://hotels.ctrip.com/hotel/guangzhou32");
		
//建立连接
URLConnection urlConnection = url.openConnection();
HttpURLConnection connection = (HttpURLConnection) urlConnection;

// 建立一个读取流从连接中读取
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));

String current; // 爬虫爬下来的每一行数据

while ((current = in.readLine()) != null) {
    System.out.pritln(current);
}

    为什么爬携程的?我爬了美团的好像是不让我爬,405权限问题blabla的。

    那么这样爬到了什么呢?

    爬到的是目标网址的前端界面源码,我们可以在网址输入目标网址去看看,按F12->Sources->双击guangzhou32

    简单易懂的java爬虫--抓取携程上的酒店信息_第1张图片

    刚刚在java Console输出的正是这三千多行前端代码。接下来我们可以对这三千多行前端代码进行处理。

    在我孜孜不倦的浏览(瞎几把看)下,终于发现了隐藏在这三千多行中的好东西。

    第2857行是这样的

    这一行很长,有25个hotelid,25个amount,也正是这一个界面给我们显示的25家酒店的信息,amount是数量的意思,这时候我猜想这个amout会不会就是酒店剩余房间,所以我隔了两分钟去刷新一下,果然amount变少了几个(话说八百多间空房,这一定是家大酒店吧)。所以说这一行有用,得做笔记。

    第2977行是这样的

    这一行可不简单,也是25家酒店的信息,包含酒店id,酒店名,酒店纬度lat,酒店经度lon(有经纬度就可以调用百度地图了嘻嘻),酒店详细信息url(相当于你点这家酒店打开的网页),酒店图片url(只有一张,是封面),酒店地址address,酒店评分score(就是4.8,4.9那玩意儿),住过该酒店的人推荐率dpscore(话说为什么要用dp,我总觉得dp是动态规划),酒店评论数dpcount,酒店星级star,酒店星级描述stardesc,酒店名缩写shortName。还挺多信息hhhh。这里我放一家酒店的例子出来。

{"id":"470094","name":"成都瑞城名人酒店","lat":"30.67645069","lon":"104.0723634",

"url":"/hotel/470094.html?isFull=F#ctm_ref=hod_sr_map_dl_txt_1",

"img":"//dimg13.c-ctrip.com/images/200t15000000xdh2l1ECD_R_300_225.jpg",

"address":"青羊区人民中路二段68号。 ( 文殊院、骡马市商业区天府广场、盐市口商业区)",

"score":"4.8","dpscore":"93","dpcount":"24653","star":"hotel_stars04","stardesc":"国家旅游局评定为四星级",

"shortName":"瑞城名人","isSingleRec":"false"},

    接下来我们就提取信息好了,这一步我是自己写的字符串查找,效率挺低的,但这不是重点,先用着!
    话不多说 直接上源码,提取相关信息到List >

package reptiletest;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;


public class Reptile {

	public static void main(String[] args) throws IOException {
		System.out.println(getHotelInfoByCity("beijing1"));
	}
	
	public static List> getHotelInfoByCity(String city) throws IOException {
		
		//首先输入要爬的网页
		URL url = new URL("https://hotels.ctrip.com/hotel/" + city);
		
		//建立连接
		URLConnection urlConnection = url.openConnection();
		HttpURLConnection connection = (HttpURLConnection) urlConnection;

		// 建立一个读取流从连接中读取
		BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));

		String current; // 爬虫爬下来的每一行数据
		boolean hadfindhtllst = false; // 是否找到关键行1
		boolean hadfindhotelPositionJSON = false; // 是否找到关键行2
		char[] htllist = new char[10005]; // 内含hotelid,酒店剩余房间数
		String roomnum = null; // 存放目标char[]->String
		char[] hotelPositionJSON = new char[50005]; // 内涵hotelid,酒店全称,酒店地址,酒店精确经纬度
		String hotelinfo = null; // 存放目标char[]->String

		while ((current = in.readLine()) != null) {
			if (hadfindhtllst == false) { // 如果还没找到关键行
				if (current.length() < 19)
					continue; // 如果该行长度小于19 直接跳过
				current.getChars(12, 19, htllist, 0);
				if (charsequals(htllist, "htllist", 7)) {
					hadfindhtllst = true; // 找到了关建行
					current.getChars(12, current.length(), htllist, 0);
					roomnum = new String(htllist, 0, current.length() - 12);
				}
			}
			if (hadfindhotelPositionJSON == false) {// 如果还没找到关键行
				if (current.length() < 25)
					continue; // 如果改行长度小于25 直接跳过
				current.getChars(8, 25, hotelPositionJSON, 0);
				if (charsequals(hotelPositionJSON, "hotelPositionJSON", 17)) {
					hadfindhotelPositionJSON = true; // 找到了关建行
					current.getChars(8, current.length(), hotelPositionJSON, 0);
					hotelinfo = new String(hotelPositionJSON, 0, current.length() - 8);
				}
			}
		}

		// 经过爬虫后,有用的信息只有 String roomnum(内含酒店id,酒店剩余房间数)
		// String hotelinfo(内含酒店id,酒店全名,酒店位置,酒店经纬度,酒店评分)
//		 System.err.println(roomnum);
//		 System.err.println(hotelinfo);
		
		if(roomnum == null || hotelinfo == null)
			return null;
		
		List> lists = new ArrayList>();

		// 添加酒店id,酒店城市,酒店余房数量
		for (int i = 0, cs = 0, now = 0; i < roomnum.length(); i++) { // cs为"出现的次数
			if (roomnum.charAt(i) == '\"') {
				cs++;
				if (cs % 8 == 3) {
					List list = new ArrayList();
					String temp = "";
					while (roomnum.charAt(++i) != '\"') temp += roomnum.charAt(i);
					i--;
					list.add(temp);
					if(city.equals("chengdu28")) {
						list.add("成都");
					}
					else if(city.equals("guangzhou32")) {
						list.add("广州");
					}
					else if(city.equals("beijing1")) {
						list.add("北京");
					}
					else {
						list.add("未知城市");
					}
					lists.add(list);
				}
				if (cs % 8 == 7) {
					String temp = "";
					while (roomnum.charAt(++i) != '\"') temp += roomnum.charAt(i);
					i--;
					lists.get(now++).add(temp);
				}
			}
		}

		// 添加酒店名,纬度lat,经度lon,酒店照片,酒店地址,酒店评分,酒店接待能力(星级)
		for (int i = 0, cs = 0, now = 0; i < hotelinfo.length(); i++) {
			if(hotelinfo.charAt(i) == '\"') {
				cs++;
				if(cs%56 == 7 || cs%56 == 11 || cs%56 == 15
						|| cs%56 == 23 || cs%56 == 27
						|| cs%56 == 31 || cs%56 == 43) {
					String temp = "";
					while (hotelinfo.charAt(++i) != '\"') temp += hotelinfo.charAt(i);
					i--;
					lists.get(now).add(temp);
				}
				
				if(cs%56 == 43)now++;
			}
		}

		return lists;
	}

	// 查询char[]型 与 String型是否相等
	public static boolean charsequals(char[] left, String right, int length) {

		boolean result = true;
		for (int i = length - 1; i >= 0; i--) {
			result &= left[i] == right.charAt(i);
		}
		return result;
	}
}

之后我把这些信息放到数据库(代码没放出来)里面,由于业务要求是定时采集信息,所以下一篇我准备写下SSM的定时器,就几行代码。

简单易懂的java爬虫--抓取携程上的酒店信息_第2张图片

ps:https://hotels.ctrip.com/hotel/guangzhou32 是广州酒店信息

        https://hotels.ctrip.com/hotel/chengdu28 是成都酒店信息

       https://hotels.ctrip.com/hotel/beijing1 是北京酒店信息(不愧是首都!)

       其他的可以自己搞搞,不麻烦。

你可能感兴趣的:(java基础,java基础爬虫)