Java爬虫入门笔记

时间:2021-06-24 16:56:51

今天一天都在想怎么爬到我需要的数据,然后用Java代码实现了一下。以前只是知道正则表达式很强大,但是看起来头晕,所以也懒得去看。
然后突然要爬数据,看到别人写的例子,一大堆的正则表达式,所以硬着头皮也去入了一个门。
附上参考网站,很给力的正则学习,30分钟真能入门。

正则表达式30分钟入门教程

1 需求:比如要从这样一个网页上抓取数据
http://map.baidu.com/detail?qt=ninf&from=housezt&detail=house&uid=5ef5edbdc64c1bb49e9d6899
Java爬虫入门笔记
这个请求最后面的uid其实是百度地图上查到该点的uid(也就是5ef5edbdc64c1bb49e9d6899),我的数据库里面已经获取了武汉的房地产的uid,现在要通过uid获取详细信息。
先从一个着手,再多的数据也是循环抓取了。

2 发送请求到网页 ,用到HttpURLConnection类
这里用别人写好的一个

package connection;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class ConnectionUtil {
    public static String Connect(String address){
        HttpURLConnection conn = null;
        URL url = null;
        InputStream in = null;
        BufferedReader reader = null;
        StringBuffer stringBuffer = null;
        try {
            url = new URL(address);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setDoInput(true);
            conn.connect();
            in = conn.getInputStream();
            reader = new BufferedReader(new      InputStreamReader(in));
            stringBuffer = new StringBuffer();
            String line = null;
            while((line = reader.readLine()) != null){
                stringBuffer.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            conn.disconnect();
            try {
                in.close();
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return stringBuffer.toString();
    }
}

3 接收服务器返回的页面html数据
返回了html字符串之后,首先要明确需要抓取的数据是哪些,分析网页的特点。
比如我现在要抓取的数据有:
Java爬虫入门笔记

        图片url
        价格
        房屋类型
        建筑类型
        建筑年代
        容积率
        物业费
        物业公司
        开发商

然后分析它的html结构:
Java爬虫入门笔记

分析好结构之后就好写正则表达式了,用来匹配获取。

4 进行解析

package main;

import connection.ConnectionUtil;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Analyze {

    //使用时调用此方法,传入uid,如 5ef5edbdc64c1bb49e9d6899,返回的是一个字符串,可以打印出来看一下
    public String regexMain(String uid) {
        String url="http://map.baidu.com/detail?qt=ninf&from=housezt&detail=house&uid="+uid;
        String result = ConnectionUtil.Connect(url);
        return getHouseInfo(result);
    }

    private String getHouseInfo(String targetStr) {

        StringBuilder lastInfo=new StringBuilder();
        //提取图片url
        Pattern imgpattern=Pattern.compile("<img class=\"img-large\".*\" />");
        Matcher imgmatcher=imgpattern.matcher(targetStr);
        while (imgmatcher.find()){
            String imgString=imgmatcher.group();
            int n=imgString.lastIndexOf("=\"");
            String imgUrl=imgString.substring(n+2,imgString.length()-3);
//System.out.println("imgRul:"+imgUrl);
            lastInfo.append("图片url:"+imgUrl+"\n");
        }
        //首先提取出包含房产信息的html片段,再分别处理
        Pattern pattern1 = Pattern
                .compile("fcg\">\\w*.+\\s*<dd>\\w*.+</dd>");
        Matcher matcher1 = pattern1.matcher(targetStr);
        String info = "";
        while (matcher1.find()) {
            info = matcher1.group();                //提取出的片段
            Pattern pattern2 = Pattern
                    .compile("f24 fcr\">[0-9]+");
            Matcher matcher2 = pattern2.matcher(info);
            while (matcher2.find()) {

                String price = matcher2.group().substring(9);    //提取出价格
//System.out.println("价格:" + price);
                lastInfo.append("价格:"+price+"元/平米\n");
            }

            Pattern pattern3 = Pattern
                    .compile("房屋类型:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher3 = pattern3.matcher(info);
            String houseType = "";            //可能有的没有
            while (matcher3.find()) {
                int n = matcher3.group().lastIndexOf(">");
                houseType = matcher3.group().substring(n + 1);
            }
//ystem.out.println("房屋类型:" + houseType);
            lastInfo.append("房屋类型:"+houseType+"\n");
            //建筑类型同理
            Pattern pattern4 = Pattern
                    .compile("建筑类型:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher4 = pattern4.matcher(info);
            String blockType = "";            //可能有的
            while (matcher4.find()) {
                int n = matcher4.group().lastIndexOf(">");
                blockType = matcher4.group().substring(n + 1);
            }
//System.out.println("建筑类型:" + blockType);
            lastInfo.append("建筑类型:"+blockType+"\n");
            //建筑年代
            Pattern pattern5 = Pattern
                    .compile("建筑年代:</dt>\\s*<dd>[0-9]+");
            Matcher matcher5 = pattern5.matcher(info);
            String blockAge = "";            //可能有的没有
            while (matcher5.find()) {
                int n = matcher5.group().lastIndexOf(">");
                blockAge = matcher5.group().substring(n + 1);
            }
//System.out.println("建筑年代:" + blockAge);
            lastInfo.append("建筑年代:"+blockAge+"\n");
            //容积率
            Pattern pattern6 = Pattern
                    .compile("容积率:</dt>\\s*<dd>[0-9]+\\.[0-9]+");
            Matcher matcher6 = pattern6.matcher(info);
            String FAR = "";            //可能有的没有
            while (matcher6.find()) {
                int n = matcher6.group().lastIndexOf(">");
                FAR = matcher6.group().substring(n + 1);
            }
//System.out.println("容积率:" + FAR);
            lastInfo.append("容积率:"+FAR+"\n");
            //物业费
            Pattern pattern9 = Pattern
                    .compile("物业费:</dt>\\s*<dd>[0-9]+\\.[0-9]+");
            Matcher matcher9 = pattern9.matcher(info);
            String fee = "";            //可能有的没有
            while (matcher9.find()) {
                int n = matcher9.group().lastIndexOf(">");
                fee = matcher9.group().substring(n + 1);
            }
//System.out.println("物业费:" + fee);
            lastInfo.append("物业费:"+fee+"元/平米/月\n");
            //物业公司
            Pattern pattern7 = Pattern
                    .compile("物业公司:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher7 = pattern7.matcher(info);
            String pManage = "";            //可能有的没有
            while (matcher7.find()) {
                int n = matcher7.group().lastIndexOf(">");
                pManage = matcher7.group().substring(n + 1);
            }
//System.out.println("物业公司:" + pManage);
            lastInfo.append("物业公司:"+pManage+"\n");
            //开发商
            Pattern pattern8 = Pattern
                    .compile("开发商:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher8 = pattern8.matcher(info);
            String company = "";            //可能有的没有
            while (matcher8.find()) {
                int n = matcher8.group().lastIndexOf(">");
                pManage = matcher8.group().substring(n + 1);
            }
//System.out.println("开发商:" + pManage);
            lastInfo.append("开发商:"+pManage+"\n");
        }
        return lastInfo.toString();
    }

}

5 获取结果

uid:5ef5edbdc64c1bb49e9d6899
图片url:http://webmap2.map.bdimg.com/maps/services/thumbnails?width=350&height=200&align=center,center&src=http://src.house.sina.com.cn/imp/imp/deal/fa/86/f/cf94afde93e3f5622746b3ec86f_p7_mk7_os02c14c_cm240X180.jpg
价格:13000元/平米
房屋类型:塔楼
建筑类型:塔楼 多层 小高层 高层水景地产 宜居生态地产 公园地产 武汉特色楼盘
建筑年代:2014
容积率:1.05
物业费:2.8元/平米/月
物业公司:碧桂园物业发展有限公司
开发商:武汉生态城碧桂园投资有限公司


2018/3/10 更新:
有人问我爬到数据之后不知道干嘛?
举个很简单的例子,
根据抓取字段建立房产数据库表:
Java爬虫入门笔记

我当时就利用百度地图加爬取得数据 做了一个简单的房产管理系统,补充一下截图:

Java爬虫入门笔记

2018/4/18 更新:
照顾到一些初学的同学,添加一点详细的东西,使之更加完善:

1.我们可以根据需要的爬到的数据字段建立一个HouseInfo对象,比如这样:

package pojo;

public class HouseInfo {

    private String uid;
    private String price;
    private String houseType;//房屋类型
    private String blockType;//建筑类型
    private String blockAge;//建筑年代
    private String FAR; //容积率
    private String fee;//物业费
    private String pManage;//物业
    private String company;//开发商
    private String imgUrl; //图片url

    public String getImgUrl() {
        return imgUrl;
    }

    public void setImgUrl(String imgUrl) {
        this.imgUrl = imgUrl;
    }

    public String getpManage() {
        return pManage;
    }
    public void setpManage(String pManage) {
        this.pManage = pManage;
    }
    public String getCompany() {
        return company;
    }
    public void setCompany(String company) {
        this.company = company;
    }
    public String getUid() {
        return uid;
    }
    public void setUid(String uid) {
        this.uid = uid;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
    public String getHouseType() {
        return houseType;
    }
    public void setHouseType(String houseType) {
        this.houseType = houseType;
    }
    public String getBlockType() {
        return blockType;
    }
    public void setBlockType(String blockType) {
        this.blockType = blockType;
    }
    public String getBlockAge() {
        return blockAge;
    }
    public void setBlockAge(String blockAge) {
        this.blockAge = blockAge;
    }
    public String getFAR() {
        return FAR;
    }
    public void setFAR(String fAR) {
        FAR = fAR;
    }
    public String getFee() {
        return fee;
    }
    public void setFee(String fee) {
        this.fee = fee;
    }

//这个方法是为了打印出来看
    @Override
    public String toString() {
        return "HouseInfo{" +
                "uid='" + uid + '\'' +
                ",\n price='" + price + '\'' +
                ",\n houseType='" + houseType + '\'' +
                ",\n blockType='" + blockType + '\'' +
                ",\n blockAge='" + blockAge + '\'' +
                ",\n FAR='" + FAR + '\'' +
                ",\n fee='" + fee + '\'' +
                ",\n pManage='" + pManage + '\'' +
                ",\n company='" + company + '\'' +
                ",\n imgUrl='" + imgUrl + '\'' +
                '}';
    }
}

2.然后我们更新一下我们爬取的代码,将需要的信息放到一个新建的HouseInfo对象里面去保存,而不是像之前直接打印出来:

package main;

import connection.ConnectionUtil;
import pojo.HouseInfo;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Analyze {

    public HouseInfo regexMain(String uid) {
        String url="http://map.baidu.com/detail?qt=ninf&from=housezt&detail=house&uid="+uid;
        String result = ConnectionUtil.Connect(url);
        HouseInfo h=getHouseInfo(result);
       h.setUid(uid);
        return h;
    }

    private HouseInfo getHouseInfo(String targetStr) {
    //houseInfo这个对象就是用来存放我们需要的信息
        HouseInfo houseInfo=new HouseInfo();
        //提取图片url
        Pattern imgpattern=Pattern.compile("<img class=\"img-large\".*\" />");
        Matcher imgmatcher=imgpattern.matcher(targetStr);
        while (imgmatcher.find()){
            String imgString=imgmatcher.group();
            int n=imgString.lastIndexOf("=\"");
            String imgUrl=imgString.substring(n+2,imgString.length()-3);
//System.out.println("imgRul:"+imgUrl);
            houseInfo.setImgUrl(imgUrl);//存图片url
        }
        //首先提取出包含房产信息的html片段,再分别处理
        Pattern pattern1 = Pattern
                .compile("fcg\">\\w*.+\\s*<dd>\\w*.+</dd>");
        Matcher matcher1 = pattern1.matcher(targetStr);
        String info = "";
        while (matcher1.find()) {
            info = matcher1.group();                //提取出的片段
            Pattern pattern2 = Pattern
                    .compile("f24 fcr\">[0-9]+");
            Matcher matcher2 = pattern2.matcher(info);
            while (matcher2.find()) {
                String price = matcher2.group().substring(9);    //提取出价格
                houseInfo.setPrice(price);//存价格
            }

            Pattern pattern3 = Pattern
                    .compile("房屋类型:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher3 = pattern3.matcher(info);
            String houseType = "";            //可能有的没有
            while (matcher3.find()) {
                int n = matcher3.group().lastIndexOf(">");
                houseType = matcher3.group().substring(n + 1);
            }
            houseInfo.setHouseType(houseType);
            //建筑类型同理
            Pattern pattern4 = Pattern
                    .compile("建筑类型:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher4 = pattern4.matcher(info);
            String blockType = "";            //可能有的
            while (matcher4.find()) {
                int n = matcher4.group().lastIndexOf(">");
                blockType = matcher4.group().substring(n + 1);
            }
            houseInfo.setBlockType(blockType);
            //建筑年代
            Pattern pattern5 = Pattern
                    .compile("建筑年代:</dt>\\s*<dd>[0-9]+");
            Matcher matcher5 = pattern5.matcher(info);
            String blockAge = "";            //可能有的没有
            while (matcher5.find()) {
                int n = matcher5.group().lastIndexOf(">");
                blockAge = matcher5.group().substring(n + 1);
            }
            houseInfo.setBlockAge(blockAge);
            //容积率
            Pattern pattern6 = Pattern
                    .compile("容积率:</dt>\\s*<dd>[0-9]+\\.[0-9]+");
            Matcher matcher6 = pattern6.matcher(info);
            String FAR = "";            //可能有的没有
            while (matcher6.find()) {
                int n = matcher6.group().lastIndexOf(">");
                FAR = matcher6.group().substring(n + 1);
            }
            houseInfo.setFAR(FAR);
            //物业费
            Pattern pattern9 = Pattern
                    .compile("物业费:</dt>\\s*<dd>[0-9]+\\.[0-9]+");
            Matcher matcher9 = pattern9.matcher(info);
            String fee = "";            //可能有的没有
            while (matcher9.find()) {
                int n = matcher9.group().lastIndexOf(">");
                fee = matcher9.group().substring(n + 1);
            }
            houseInfo.setFee(fee);
            //物业公司
            Pattern pattern7 = Pattern
                    .compile("物业公司:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher7 = pattern7.matcher(info);
            String pManage = "";            //可能有的没有
            while (matcher7.find()) {
                int n = matcher7.group().lastIndexOf(">");
                pManage = matcher7.group().substring(n + 1);
            }
            houseInfo.setpManage(pManage);
            //开发商
            Pattern pattern8 = Pattern
                    .compile("开发商:</dt>\\s*<dd>[\\u4e00-\\u9fa5]+( *[\\u4e00-\\u9fa5]+)*");
            Matcher matcher8 = pattern8.matcher(info);
            String company = "";            //可能有的没有
            while (matcher8.find()) {
                int n = matcher8.group().lastIndexOf(">");
                company = matcher8.group().substring(n + 1);
            }
            houseInfo.setCompany(company);
        }
        return houseInfo;
    }


//最后我们运行main方法测试一下:
    public static void main(String[] args) {
        HouseInfo info = new Analyze().regexMain("5ef5edbdc64c1bb49e9d6899");
        System.out.println(info);
    }
}

运行main方法看到控制台打印:

HouseInfo{uid='5ef5edbdc64c1bb49e9d6899', price='35000', houseType='独栋 联排', blockType='双拼 联排 多层 小高层 高层', blockAge='2015', FAR='1.05', fee='2.8', pManage='碧桂园物业发展有限公司', company='武汉生态城碧桂园投资有限公司', imgUrl='http://webmap2.map.bdimg.com/static/house/widget/index/basicinfo/images/no-pic-large_abf3a16.png"'}

由于这篇文章是以前写的,过去有快一年了,点击上面的imgUrl可以看到现在那个页面图片现在可能没有正常显示,但这不影响学习。

Java爬虫入门笔记