代码改变世界

Java爬虫

2017-11-22 23:14  晨曦曙光  阅读(288)  评论(0编辑  收藏  举报

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

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

  服务器端发出的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
View Code

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;
    }
    
}
View Code

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;
    }
     
}
View Code