spider爬虫练习
package com.jinzhi.spider;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.stream.events.StartDocument;
//多线程类,爬虫程序要用多线程来处理网页内容的爬取,效率更高
public class SearchCrawler implements Runnable {
/**
*
* disallowListCache缓存robot不允许搜索的URL。
* Robot协议在Web站点的根目录下设置一个robots.txt文件,
* 规定站点上的哪些页面是限制搜索的。 搜索程序应该在搜索过程中跳过这些区域
*
**/
//不允许搜索的URL缓存
private HashMap<String, ArrayList<String>> disallowListCache = new HashMap<String, ArrayList<String>>();//设置一存储限制搜索的区域
ArrayList<String> errorList = new ArrayList<String>();//错误链接集合
public ArrayList<String> result = new ArrayList<>();//结果集合
String startUrl;//开始搜索的起点
int maxUrl;//最大处理的url数;
String searchString;//要搜索的字符串(英文)
boolean caseSensitive = false;//大小写是否敏感
boolean limitHost = false;//是否在限制的主机内搜索
//请求任务URL,根据得到的URL下载相应的HTML代码,利用HTML代码调用其他模块完成相关处理。
public SearchCrawler(String startUrl, int maxUrl, String searchString) {
this.startUrl = startUrl;
this.maxUrl = maxUrl;
this.searchString = searchString;
}
//得到结果——结果肯定不是一个字符串,所以选择用字符串集合,
public ArrayList<String> getResult() {
return result;
}
//启动搜索线程
public void run() {
//真正查询操作
crawl(startUrl, maxUrl, searchString, limitHost, caseSensitive);
}
//把url包装为URL类
private URL verifyUrl(String url) {
//不是以Http://开头则返回null
if(!url.toLowerCase().startsWith("http://"))
//方法直接返回
return null;
//声明一个新的url
URL verifiedUrl = null;
try {
//用传递进来的url包装一个URL
verifiedUrl = new URL(url);
} catch (Exception e) {
//否则
return null;
}
//把包装好的URL对象返回
return verifiedUrl;
}
//检测URL是否允许被使用
private boolean isRobotAllowed(URL urlToCheck) {
//通过URL获取给出对应的主机
String host = urlToCheck.getHost().toLowerCase();
//通过主机获取url集合,通过Map键值对的形式,获取主机不允许搜索的URL(是以ArrayList的形式标识)缓存
ArrayList<String> disallowList = disallowListCache.get(host);
//如果没有缓存,下载并缓存
if(disallowList == null) {
disallowList = new ArrayList<>();
try {
//准备记录不允许搜索的URL
URL robotsFileUrl = new URL("http://" + host + "/robots.txt");
//把不允许搜索的URL实例获取的字节流转换为字符流 //打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。
BufferedReader reader = new BufferedReader(new InputStreamReader(robotsFileUrl.openStream()));
//读取robot文件,创建不允许访问的路径列表
String line;//设置字符串缓冲区
//不等于空就继续读取
while((line=reader.readLine())!=null) {
//判断是否包含字符串Disallow
if(line.indexOf("Disallow:") == 0) {
//获取不允许访问路径—— 1.去除Disallow:
String disallowPath = line.substring("Disallow:".length());
//检测是否有注释
int commenIndex = disallowPath.indexOf("#");
if(commenIndex != -1) {
// 2.去掉注释
disallowPath = disallowPath.substring(0, commenIndex);
}
// 3. 去掉空格
disallowPath = disallowPath.trim();
//把不允许访问路径添加到不允许访问集合记录起来
disallowList.add(disallowPath);
}
}
//缓存此主机不允许访问的路径
disallowListCache.put(host, disallowList);
} catch (Exception e) {
//web站点根目录下没有robots.txt文件,返回真
return true;
}
}
//从参数URL中得到文件
String file = urlToCheck.getFile();
//遍历不允许访问路径记录的集合
for(int i = 0; i < disallowList.size(); i++) {
//得到每一个不允许访问的路径
String disallow = disallowList.get(i);
//判断从给出的URL得到的文件如果为不被允许访问的文件
if(file.startsWith(disallow)) {
//返回false;
return false;
}
}
//否则,返回真
return true;
}
//下载页面
public String downloadPage(URL pageUrl) {
try {
//根据URL初始化缓冲字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(pageUrl.openStream()));
String line;//设置字符串缓冲区
StringBuffer pageBuffer = new StringBuffer();
while((line = reader.readLine()) != null) {
//把页面数据添加到字符串缓冲区
pageBuffer.append(line);
}
//返回下载的数据
return pageBuffer.toString();
} catch (Exception e) {
// TODO: handle exception
}
//否则,返回null
return null;
}
//去除url中的"www"
private String removeWwwFromUrl(String url) {
//获取"://www."的位置
int index = url.indexOf("://www.");
if(index != -1) {
//如果存在,刚好截取出:www
return url.substring(0, index + 3) + url.substring(index + 7);
}
return (url);
}
//查找目标链接
private ArrayList<String> retrieveLinks(URL pageUrl, String pageContents, HashSet crawledList, boolean limitHost) {
//用正则表达式编译链接的匹配模式
Pattern p = Pattern.compile("<a\\s+href\\s*=\\s*\"?(.*?)[\"|>]",Pattern.CASE_INSENSITIVE);
//看页面内容是否和正则表达式匹配
Matcher m = p.matcher(pageContents);
//准备好链接集合
ArrayList<String> linkList = new ArrayList<>();
while(m.find()) {
//得到匹配正则分组的第1组
String link = m.group(1).trim();
if(link.length() < 1) {
//证明没有目标链接
continue;
}
//跳过链到本页面的内链接
if(link.charAt(0) == '#') {
//敏感资源链接
continue;
}
if(link.indexOf("mailto:") != -1) {
//如果包含mailto:也跳过
continue;
}
if(link.toLowerCase().indexOf("javascript") != -1) {
//如果包含javascript也跳过
continue;
}
//如果存在"://"字符串,则证明找到目标链接
if(link.indexOf("://") == -1) {
//处理绝对地址——如果是:以/开头的地址链接
if(link.charAt(0) == '/') {
//拼成完整路径
link = "http://" + pageUrl.getHost() + ":" + pageUrl.getPort() + link;
} else {
String file = pageUrl.getFile();
//处理相对地址——如果存在:/字符
if(file.indexOf('/') == -1) {
link = "http://" + pageUrl.getHost() + ":"+ pageUrl.getPort() + "/" +link;
}
}
}
int index = link.indexOf("#");
//如果连接URL存在#——存在注解
if(index != -1) {
link = link.substring(0, index);
}
//去除www
link = removeWwwFromUrl(link);
//封装为已证实的url
URL verifiedLink = verifyUrl(link);
if(verifiedLink == null) {
//不是目标链接
continue;
}
//如果限定主机,排除那些不合条件的URL为未证实(非目标URL)
if(limitHost && !pageUrl.getHost().toLowerCase().equals(verifiedLink.getHost().toLowerCase())) {
continue;
}
//跳过已处理的连接
if(crawledList.contains(link)) {
//处理过的链接集合中包括正在处理的连接,直接跳过
continue;
}
//把符合标准的链接放入集合中
linkList.add(link);
}
//返回集合
return (linkList);
}
//判断有无目标字符串
private boolean searchStringMatches(String pageContents, String searchString, boolean caseSensitive) {
String searchContents = pageContents;
//大小写不敏感
if(!caseSensitive) {
searchContents = pageContents.toLowerCase();
}
Pattern p = Pattern.compile("[\\s]+");//这里查询s为核武
String[] terms = p.split(searchString);
for(int i = 0; i < terms.length; i++) {
if(caseSensitive) {
if(searchContents.indexOf(terms[i]) == -1) {
return false;
}
}
}
return true;
}
//执行实际的搜索操作
public ArrayList<String> crawl(String startUrl, int maxUrls,
String searchString, boolean limithost, boolean caseSensitive) {
//初始化一个已处理连接的集合
HashSet<String> crawledList = new HashSet<String>();
LinkedHashSet<String> toCrawlList = new LinkedHashSet<String>();
//最大URL处理数<1——这里链接的url里没有有用信息
if (maxUrls < 1) {
//判断用户给定要获取的URL的处理数——如果输入错误数据,则记录在集合里
errorList.add("Invalid Max URLs value.");
System.out.println("Invalid Max URLs value.");
}
//用户给定的目标字符串长度小于1
if (searchString.length() < 1) {
//记录入错误链接集合
errorList.add("Missing Search String.");
System.out.println("Missing search String");
}
//错误链接集合有元素,则返回该集合
if (errorList.size() > 0) {
System.out.println("err!!!");
return errorList;
}
// 从开始URL中移出www
startUrl = removeWwwFromUrl(startUrl);
//把移除"www"的url添加到url等待队列
toCrawlList.add(startUrl);
//等待队列有元素
while (toCrawlList.size() > 0) {
//用户给定获取的URL数量
if (maxUrls != -1) {
//当已获取的有效链接数和用户想要得到的链接数相同时——达到目标数目
if (crawledList.size() == maxUrls) {
//终止循环
break;
}
}
// 从等待队列中获取url
String url = toCrawlList.iterator().next();
//从等待队列中去除该url
toCrawlList.remove(url);
//url——>URL
URL verifiedUrl = verifyUrl(url);
//查看是否被允许访问
if (!isRobotAllowed(verifiedUrl)) {
//如果是不允许被访问的URL
continue;
}
// 增加已处理的URL到crawledList
crawledList.add(url);
//根据URL下载页面得到目的字符串
String pageContents = downloadPage(verifiedUrl);
if (pageContents != null && pageContents.length() > 0) {
// 从页面中获取目的链接
ArrayList<String> links = retrieveLinks(verifiedUrl,
pageContents, crawledList, limitHost);
//目的链接加入等待队列
toCrawlList.addAll(links);
if (searchStringMatches(pageContents, searchString,
caseSensitive)) {
//如果有目标字符串,则把URL记录到结果集里边
result.add(url);
System.out.println(url);
}
}
}
return result;
}
// 主函数
public static void main(String[] args) {
SearchCrawler crawler = new SearchCrawler(
"http://www.sohu.com",20,"N");
//创建线程
Thread search = new Thread(crawler);
System.out.println("Start searching...");
System.out.println("result:");
//启动线程
search.start();
try {
//等待线程执行完毕后执行——执行完毕的标志
search.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行截图如下:
虽然达到了预期的效果,但是还有很多不足的地方,也没有友好的界面,我将继续改进。
spider爬虫练习的更多相关文章
- spider 爬虫文件基本参数(3)
一 代码 # -*- coding: utf-8 -*- import scrapy class ZhihuSpider(scrapy.Spider): # 爬虫名字,名字唯一,允许自定义 name ...
- Spider爬虫 の 事
初识Spider_Man(爬爬虫) Spider_Man_2 の requests模块 Spider_Man_3 の selenium Spider_Man_4 の BeautifulSo ...
- Spider爬虫-get、post请求
1:概念: 爬虫就是通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程. 2:python爬虫与其他语言的比较: (1)php爬虫弊端:多进程多线程支持的不好 (2)java:代码臃肿,重 ...
- burp suite之spider(爬虫)
spider (蜘蛛,这里的意思指爬行) 像蜘蛛一样在网站上爬行出网站的个个目录信息,并发送至Target. 1.Control(控制) Spider is paused :停止蜘蛛爬行 Clear ...
- Spider爬虫基础
get获取某个网站的html代码,post访问网站获取网站返回的信息 import urllib.request import urllib.parse #使用get请求 def start1(): ...
- Spider爬虫清洗数据(re方法)
import re s0 = 'BOY and GIRL' s1 = re.sub(r'BOY|GIRL', 'HUMAN', s0) print s1 # HUMAN and HUMAN 替换方法.
- 第十六节:Scrapy爬虫框架之项目创建spider文件数据爬取
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取所设计的, 也可以应用在获取API所返回的数据或 ...
- Golang tool:include spider library,image library and some other db library such as mysql,redis,mogodb,hbase,cassandra
一.Go_tool This is a tool library for Golang.Dont't worry about not understant it! All comment writes ...
- python爬虫学习--防盗链
一 首先要了解什么是盗链 盗链是指服务提供商自己不提供服务的内容,通过技术手段绕过其它有利益的最终用户界面(如广告),直接在自己的网站上向最终用户提供其它服务商的服务内容,骗取最终用户的浏览和点击率. ...
随机推荐
- php基础--来自网页转载
注意:1.网页文件放在wamp中的www文件下:2.www文件下不能出现中文:网页浏览的方法:1.没有建立站点:localhost/文件所在位置2.建立站点:(1)站点-新建站点-打开对话框 (2)修 ...
- reference to 'map' is ambiguous|
reference to 'map' is ambiguous| c++编译出现此错误 表明定义的变量名字map和库函数map冲突而产生歧义
- 一个LinkedBlockingQueue线程安全的例子
一个LinkedBlockingQueue线程安全的例子 package llj.mf.ace; import java.util.ArrayList; import java.util.HashSe ...
- 前端面试题汇总(主要为 Vue)
前端面试题汇总 1. 谈谈你对MVVM开发模式的理解 MVVM分为Model.View.ViewModel三者. 1)Model:代表数据模型,数据和业务逻辑都在Model层中定义: 2)View:代 ...
- Window Server配置Flask
1.安装了Chrome 2.安装git 3.创建SSH key:ssh-keygen -t rsa -C "youremail@example.com" 4.安装notepad++ ...
- windows下安装php reids扩展
1.使用phpinfo()函数查看PHP的版本信息,这会决定扩展文件版本. 2.下载php_igbinary-1.2.1-5.5-ts-vc11-x64.zip,php_redis-2.2.5-5.6 ...
- [LeetCode] 132. Palindrome Partitioning II_ Hard tag: Dynamic Programming
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...
- django js引入失效问题
今天将项目中html文件下的自定义scrept代码单独独立,结果js引入无效,没有任何时间效果,在浏览器查看引入文件也正常. 后来发现自己引入的位置不对,js的引入文件应该放在body体内,而我把他们 ...
- Windows Java安装
jdk安装与配置jdk for windows1.下载官网地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html2. ...
- CF830A Office Keys(贪心)
CF830A Office Keys [题目链接]CF830A Office Keys [题目类型]贪心 &题意: 有n个人,k个钥匙,一个目的地,求让n个人都回到目的地的最短时间,每个人都要 ...