原文链接:https://www.cnblogs.com/sanmubird/p/7857474.html
网络爬虫是做什么的?
他的主要工作就是 跟据指定的url地址 去发送请求,获得响应, 然后解析响应 , 一方面从响应中查找出想要查找的数据,另一方面从响应中解析出新的URL路径
然后继续访问,继续解析;继续查找需要的数据和继续解析出新的URL路径
一个简单的爬虫 必需的功能:
1: 发送请求和获取响应的功能
2: 解析响应的功能
3: 对 过滤出的数据 进行存储 的功能
4: 对解析出来的URL路径 处理的功能
1、pom.xml文件
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>com.googlecode.juniversalchardet</groupId>
<artifactId>juniversalchardet</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>org.kie.modules</groupId>
<artifactId>org-apache-commons-httpclient</artifactId>
<version>6.2.0.CR2</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.3</version>
</dependency>
2、util类
package com.etoak.crawl.util;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import com.etoak.crawl.page.Page;
import com.etoak.crawl.page.PageParserTool;
import org.apache.commons.lang3.StringUtils;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
/* 本类主要是 下载那些已经访问过的文件*/
public class FileTool {
private static String dirPath;
/**
* getMethod.getResponseHeader("Content-Type").getValue()
* 根据 URL 和网页类型生成需要保存的网页的文件名,去除 URL 中的非文件名字符
*/
private static String getFileNameByUrl(String url, String contentType) {
//去除 http://
url = url.substring(7);
//text/html 类型
if (contentType.indexOf("html") != -1) {
url = url.replaceAll("[\\?/:*|<>\"]", "_") + ".html";
return url;
}
//如 application/pdf 类型
else {
return url.replaceAll("[\\?/:*|<>\"]", "_");// + "." + contentType.substring(contentType.lastIndexOf("/") + 1)
}
}
/*
* 生成目录
* */
private static void mkdir() {
// String url = "temp\\templates\\images\\";
// String url1 = "temp\\templates\\js\\";
// String url2 = "temp\\templates\\css\\";
if (dirPath == null) {
//只能新建最后一个文件夹
dirPath = Class.class.getClass().getResource("/").getPath() + "temp\\templates\\02\\";
}
File fileDir = new File(dirPath);
if (!fileDir.exists()) {
fileDir.mkdir();
}
}
/**
* 保存网页字节数组到本地文件,filePath 为要保存的文件的相对地址
*/
public static void saveToLocal(Page page) {
mkdir();
String fileName = getFileNameByUrl(page.getUrl(), page.getContentType());
String s = StringUtils.substringAfterLast(fileName, "_");
//System.out.println("文件名:"+s);
String filePath = dirPath + s;
byte[] data = page.getContent();
try {
//Files.lines(Paths.get("D:\\jd.txt"), StandardCharsets.UTF_8).forEach(System.out::println);
DataOutputStream out = new DataOutputStream(new FileOutputStream(new File(filePath)));
for (int i = 0; i < data.length; i++) {
out.write(data[i]);
}
out.flush();
out.close();
System.out.println("文件:'"+ s + "'已经被存储在"+ filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、执行
package com.etoak.crawl.main;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import com.etoak.crawl.link.LinkFilter;
import com.etoak.crawl.link.Links;
import com.etoak.crawl.page.Page;
import com.etoak.crawl.page.PageParserTool;
import com.etoak.crawl.page.RequestAndResponseTool;
import com.etoak.crawl.util.FileTool;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.Set;
public class MyCrawler {
/**
* 使用种子初始化 URL 队列
*
* @param seeds 种子 URL
* @return
*/
private void initCrawlerWithSeeds(String[] seeds) {
for (int i = 0; i < seeds.length; i++) {
Links.addUnvisitedUrlQueue(seeds[i]);
}
}
public static String url = "http://moe.005.tv/";
public void crawling2(String[] seeds) {
//初始化 URL 队列
initCrawlerWithSeeds(seeds);
//定义过滤器,提取以 http://www.baidu.com 开头的链接
LinkFilter filter = new LinkFilter() {
public boolean accept(String url) {
if (url.startsWith(url))
return true;
else
return false;
}
};
//循环条件:待抓取的链接不空且抓取的网页不多于 1000
while (!Links.unVisitedUrlQueueIsEmpty() && Links.getVisitedUrlNum() <= 1000) {
//先从待访问的序列中取出第一个;
String visitUrl = (String) Links.removeHeadOfUnVisitedUrlQueue();
if (visitUrl == null) {
continue;
}
//网页地址
String filePath = "F:\\QQ\\crawl\\crawl\\target\\classes\\temp\\templates\\02\\www.kt.com_.html";
//根据URL得到page;
Page page = RequestAndResponseTool.sendRequstAndGetResponse(visitUrl);
Elements es = PageParserTool.select(page, "img");
Iterator iterator = es.iterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
String src = element.attr("src");
if (src.indexOf("?") != -1) {
continue;
}
src = src.substring(src.lastIndexOf("/") + 1);
element.attr("src", src);
}
es = PageParserTool.select(page, "link");
iterator = es.iterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
if (element.hasAttr("href")) {
String href = element.attr("href");
if (href.indexOf("?") != -1) {
continue;
}
href = href.substring(href.lastIndexOf("/") + 1);
element.attr("href", href);
}
}
es = PageParserTool.select(page, "script");
iterator = es.iterator();
while (iterator.hasNext()) {
Element element = (Element) iterator.next();
String src = element.attr("src");
if (src.indexOf("?") != -1) {
continue;
}
src = src.substring(src.lastIndexOf("/") + 1);
element.attr("src", src);
}
try {
File file = new File(filePath);
PrintStream ps = new PrintStream(new FileOutputStream(file));
ps.append(page.getDoc().toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
/**
* 抓取过程
*
* @param seeds
* @return
*/
public void crawling(String[] seeds) {
//初始化 URL 队列
initCrawlerWithSeeds(seeds);
//定义过滤器,提取以 http://www.baidu.com 开头的链接
LinkFilter filter = new LinkFilter() {
public boolean accept(String url) {
if (url.startsWith(url))
return true;
else
return false;
}
};
//循环条件:待抓取的链接不空且抓取的网页不多于 1000
while (!Links.unVisitedUrlQueueIsEmpty() && Links.getVisitedUrlNum() <= 1000) {
//先从待访问的序列中取出第一个;
String visitUrl = (String) Links.removeHeadOfUnVisitedUrlQueue();
if (visitUrl == null) {
continue;
}
//根据URL得到page;
Page page = RequestAndResponseTool.sendRequstAndGetResponse(visitUrl);
// //对page进行处理: 访问DOM的某个标签
Elements es = PageParserTool.select(page, "a");
if (!es.isEmpty()) {
//System.out.println("下面将打印所有a标签: ");
//System.out.println(es);
}
//将保存文件
FileTool.saveToLocal(page);
//将已经访问过的链接放入已访问的链接中;
Links.addVisitedUrlSet(visitUrl);
//得到超链接
Set<String> links = PageParserTool.getLinks(page, "img");
for (String link : links) {
//注意:执行的时候最好注释其他方法,这样不容易报错,速度也较快
//Links.addUnvisitedUrlQueue(link);
System.out.println("新增爬取img路径: " + link);
}
//得到css
links = PageParserTool.getLinks(page, "link");
for (String link : links) {
Links.addUnvisitedUrlQueue(link);
System.out.println("新增爬取link路径: " + link);
}
//得到js
links = PageParserTool.getLinks(page, "script");
for (String link : links) {
Links.addUnvisitedUrlQueue(link);
System.out.println("新增爬取script路径: " + link);
}
}
}
//main 方法入口
public static void main(String[] args) {
MyCrawler crawler = new MyCrawler();
crawler.crawling2(new String[]{url});
crawler.crawling(new String[]{url});
}
}
效果如下
想要原码的可以到最上面的链接copy