Java爬虫

1.网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。

2.那么程序获取网页的原理到底是怎么回事呢?看下面的图:客服端首先向服务器端发出Http请求,之后服务器端返回相应的结果或者请求超时客户端自己报错。

image

服务器端发出的Http请求,实际上说是对服务器的文件的请求。下面的表格是一些常见的HTTP请求对应的文件。(因为第一列给出的都是主机的网址信息,主机一般都通过配置文件将该请求转换为网站主页地址index.php或index.jsp或者index.html等)

3.Java爬虫的代码实现
1)dbcp.properties

`########DBCP配置文件##########
#驱动名
driverClassName=com.mysql.jdbc.Driver
#url
url=jdbc:mysql://127.0.0.1:3306/peoper?useSSL=false
#用户名
username=root
#密码
password=sbj174615
#初试连接数
initialSize=30
#最大活跃数
maxTotal=30
#最大idle数
maxIdle=10
#最小idle数
minIdle=5
#最长等待时间(毫秒)
maxWaitMillis=1000
#程序中的连接不使用后是否被连接池回收(该版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
#removeAbandoned=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#连接在所指定的秒数内未使用才会被删除(秒)(为配合测试程序才配置为1秒)
removeAbandonedTimeout=1

2)DBCPUtil.java

package com.j1702.db;

import java.io.FileInputStream;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSourceFactory;





/**
 * DBCP配置类
 * @author SUN
 */
public class DBCPUtil {
     private static Properties properties = new Properties();
        private static DataSource dataSource;
        //加载DBCP配置文件
        static{
            try{
                properties.load(DBCPUtil.class.getClassLoader().getResourceAsStream("dbcp.properties"));
                dataSource = BasicDataSourceFactory.createDataSource(properties);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    
    //从连接池中获取一个连接
    //从连接池中获取一个连接
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    
}

3)java爬虫

package com.rimi.pachong;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.j1702.db.DBCPUtil;
 
public class pachong1 {
    
    public static void main(String[] args) {
        pachong1 videoLinkGrab = new pachong1();
        videoLinkGrab.saveData("http://www.80s.tw/movie/list/q----");
    }
 
    /**
     * 将获取到的数据保存在数据库中
     * 
     * @param baseUrl
     *            爬虫起点
     * @return null
     * */
    public void saveData(String baseUrl) {
        Map<String, Boolean> oldMap = new LinkedHashMap<String, Boolean>(); // 存储链接-是否被遍历
 
        Map<String, String> videoLinkMap = new LinkedHashMap<String, String>(); // 视频下载链接
        String oldLinkHost = ""; // host
 
        Pattern p = Pattern.compile("(https?://)?[^/\\s]*"); // 比如:http://www.zifangsky.cn
        Matcher m = p.matcher(baseUrl);
        if (m.find()) {
            oldLinkHost = m.group();
        }
 
        oldMap.put(baseUrl, false);
        videoLinkMap = crawlLinks(oldLinkHost, oldMap);
        
        // 遍历,然后将数据保存在数据库中
        try {
        
            Connection connection=DBCPUtil.getConnection();
            for (Map.Entry<String, String> mapping : videoLinkMap.entrySet()) {
                String  sql ="insert into movie(MovieName,MovieLink) values(?,?)";
                PreparedStatement ptmt =connection.prepareStatement(sql);
                
                ptmt.setString(1, mapping.getKey());
                ptmt.setString(2, mapping.getValue());
                ptmt.execute();
                
                connection.commit();
            //  System.out.println(mapping.getKey() + " : " + mapping.getValue());
            }
            
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 抓取一个网站所有可以抓取的网页链接,在思路上使用了广度优先算法 对未遍历过的新链接不断发起GET请求, 一直到遍历完整个集合都没能发现新的链接
     * 则表示不能发现新的链接了,任务结束
     * 
     * 对一个链接发起请求时,对该网页用正则查找我们所需要的视频链接,找到后存入集合videoLinkMap
     * 
     * @param oldLinkHost
     *            域名,如:http://www.zifangsky.cn
     * @param oldMap
     *            待遍历的链接集合
     * 
     * @return 返回所有抓取到的视频下载链接集合
     * */
    private Map<String, String> crawlLinks(String oldLinkHost,
            Map<String, Boolean> oldMap) {
        Map<String, Boolean> newMap = new LinkedHashMap<String, Boolean>(); // 每次循环获取到的新链接
        Map<String, String> videoLinkMap = new LinkedHashMap<String, String>(); // 视频下载链接
        String oldLink = "";
 
        for (Map.Entry<String, Boolean> mapping : oldMap.entrySet()) {
            // System.out.println("link:" + mapping.getKey() + "--------check:"
            // + mapping.getValue());
            // 如果没有被遍历过
            if (!mapping.getValue()) {
                oldLink = mapping.getKey();
                // 发起GET请求
                try {
                    URL url = new URL(oldLink);
                    HttpURLConnection connection = (HttpURLConnection) url
                            .openConnection();
                    connection.setRequestMethod("GET");
//                    connection.setConnectTimeout(6000);
//                    connection.setReadTimeout(6000);
 
                    if (connection.getResponseCode() == 200) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader reader = new BufferedReader(
                                new InputStreamReader(inputStream, "UTF-8"));
                        String line = "";
                        Pattern pattern = null;
                        Matcher matcher = null;
                        //电影详情页面,取出其中的视频下载链接,不继续深入抓取其他页面
                        if(isMoviePage(oldLink)){
                            boolean checkTitle = false;
                            String title = "";
                            while ((line = reader.readLine()) != null) {
                                //取出页面中的视频标题
                                if(!checkTitle){
                                    pattern = Pattern.compile("([^\\s]+).*?</title>");
                                    matcher = pattern.matcher(line);
                                    if(matcher.find()){
                                        title = matcher.group(1);
                                        checkTitle = true;
                                        continue;
                                    }
                                }
                                // 取出页面中的视频下载链接
                                pattern = Pattern
                                        .compile("(thunder:[^\"]+).*thunder[rR]es[tT]itle=\"[^\"]*\"");
                                matcher = pattern.matcher(line);
                                if (matcher.find()) {
                                    videoLinkMap.put(title,matcher.group(1));
                                    System.out.println("视频名称: "
                                            + title + "  ------  视频链接:"
                                            + matcher.group(1));
                                    break;  //当前页面已经检测完毕
                                }
                            }  
                        }
                        //电影列表页面
                        else if(checkUrl(oldLink)){
                            while ((line = reader.readLine()) != null) {
 
                                pattern = Pattern
                                        .compile("<a href=\"([^\"\\s]*)\"");
                                matcher = pattern.matcher(line);
                                while (matcher.find()) {
                                    String newLink = matcher.group(1).trim(); // 链接
                                    // 判断获取到的链接是否以http开头
                                    if (!newLink.startsWith("http")) {
                                        if (newLink.startsWith("/"))
                                            newLink = oldLinkHost + newLink;
                                        else
                                            newLink = oldLinkHost + "/" + newLink;
                                    }
                                    // 去除链接末尾的 /
                                    if (newLink.endsWith("/"))
                                        newLink = newLink.substring(0,
                                                newLink.length() - 1);
                                    // 去重,并且丢弃其他网站的链接
                                    if (!oldMap.containsKey(newLink)
                                            && !newMap.containsKey(newLink)
                                            && (checkUrl(newLink) || isMoviePage(newLink))) {
                                        System.out.println("temp: " + newLink);
                                        newMap.put(newLink, false);
                                    }
                                }
                            }
                        }
 
                        reader.close();
                        inputStream.close();
                    }
                    connection.disconnect();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
 
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                oldMap.replace(oldLink, false, true);
            }
        }
        // 有新链接,继续遍历
        if (!newMap.isEmpty()) {
            oldMap.putAll(newMap);
            videoLinkMap.putAll(crawlLinks(oldLinkHost, oldMap)); // 由于Map的特性,不会导致出现重复的键值对
        }
        return videoLinkMap;
    }
     
    /**
     * 判断是否是2015年的电影列表页面
     * @param url 待检查URL
     * @return 状态
     * */
    public boolean checkUrl(String url){
        Pattern pattern =  Pattern.compile("http://www.80s.tw/movie/list/q----\\d*");
        Matcher matcher = pattern.matcher(url);
        if(matcher.find())
            return true;  //2015年的列表
        else
            return false;
    }
     
    /**
     * 判断页面是否是电影详情页面
     * @param url  页面链接
     * @return 状态
     * */
    public boolean isMoviePage(String url){
        Pattern pattern =  Pattern.compile("http://www.80s.tw/movie/\\d+");
        Matcher matcher = pattern.matcher(url);
        if(matcher.find())
            return true;  //电影页面
        else 
            return false;
    }
     
}

欢迎加入学习交流群569772982,大家一起学习交流。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,103评论 18 139
  • 一、概念(载录于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434阅读 8,295评论 6 152
  • 121. 登录https://mp.weixin.qq.com 可以注册了 2.你会发现需要组织机构代码,没关系 ...
    冉冉升起的小太阳阅读 173评论 0 0
  • 洛桑陀美上师:《和谐中的圆满》—【愚痴无明】 愚昧无知之人,即使进入佛门,也不能了知正法的句义,没有闻思修习...
    祥云_17ec阅读 599评论 0 1
  • 权力的游戏是很火的一部美剧,以奇幻题材的宏大叙事和浪漫想象而受到很多热捧拥趸。在中国历史上也有一段堪称精彩的群里的...
    倪瓒阅读 1,250评论 0 4