***intell idea的使用
设置mavende本地仓库:file-》settings-〉build-》build tools-〉maven-》配置maven的环境,maven home directory,user setting files,local repository
***java 中常用框架
**mycat:数据库操作;
https://www.cnblogs.com/fyy-hhzzj/p/9044775.html
mycat分布式数据库的中间件;对读写分离,分库分表支持.
mysql单表可以存储1000万条数据,超过了就要进行分库分表设计.
使用的时候需要有四个配置文件:server.xml、schema.xml、rule.xml(分片的算法)、sequence_db_conf.properties;
Mycat的默认端口是:8066
使用步骤:下载mycat、启动mycat、
**HBase
**Zookeeper分布式自增主键
**Webmagic爬虫框架:http://git.oschina.net/flashsword20/webmagic
文档:http://webmagic.io/、http://webmagic.io/docs/zh
webmagic大致工作流程:请求网址-》Downloader下载网页-〉PageProcessor解析网页,解析出更多的网址-》Pipeline负责抽取结果的处理或者继续request请求,之类要Scheduler做去重管理,-〉继续Downloader下载网页,-》PageProcessor解析网页,-〉Pipeline负责抽取结果的处理.
需要使用代理ip,设置成动态的代理ip;
Selenium是一个模拟浏览器进行页面渲染的工具,WebMagic依赖Selenium进行动态页面的抓取,可以对 JavaScript 生成信息进行抽取;
chromeDriver是谷歌开发的自动化测试接口;
HttpClient是Http请求组件,Jsoup是网页解析器(内置了Http请求功能).
WebMagic使用Jsoup作为HTML解析工具,
爬虫的分类:分布式和单机,分布式主要就是apache的nutch框架,java实现,依赖hadoop运行,学习难度高,一般只用来做搜索引擎开发。
java单机的框架有:webmagic和webcollector以及crawler4j.
python单机的框架:scrapy和pyspider.
webmagic-selenium支持动态网页的爬取,webmagic-saxon支持X-Path和XSLT的解析.
WebMagic的代码分为两部分:webmagic-core和webmagic-extension,WebMagic支持使用独有的注解风格编写一个爬虫,引入webmagic-extension包即可使用此功能。
WebMagic由四个组件(Downloader、PageProcessor、Scheduler、Pipeline)构成。Spider是内部流程的核心,四大组件都是它的属性。
1.Downloader
Downloader负责从互联网上下载页面,以便后续处理。WebMagic默认使用了Apache HttpClient作为下载工具。
2.PageProcessor
PageProcessor负责解析页面,抽取有用信息,以及发现新的链接。WebMagic使用Jsoup作为HTML解析工具,并基于其开发了解析XPath的工具Xsoup。
在这四个组件中,PageProcessor对于每个站点每个页面都不一样,是需要使用者定制的部分。
3.Scheduler
Scheduler负责管理待抓取的URL,以及一些去重的工作。WebMagic默认提供了JDK的内存队列来管理URL,并用集合来进行去重。也支持使用Redis进行分布式管理。
除非项目有一些特殊的分布式需求,否则无需自己定制Scheduler。
4.Pipeline
Pipeline负责抽取结果的处理,包括计算、持久化到文件、数据库等。WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。
Pipeline定义了结果保存的方式,如果你要保存到指定数据库,则需要编写对应的Pipeline。对于一类需求一般只需编写一个Pipeline。
** Spider也是WebMagic操作的入口,它封装了爬虫的创建、启动、停止、多线程等功能。
public static void main(String[] args){
//使用一个PageProcessor创建一个Spider对象
Spider.create(new ListPageProcesser())
//第一个需要爬取的地址,从https://github.com/code4craft开始抓
.addUrl("https://github.com/code4craft")
//设置Scheduler,使用Redis来管理URL队列
.setScheduler(new RedisScheduler("localhost"))
//设置Pipeline,将结果以json方式保存到文件
.addPipeline(new JsonFilePipeline("D:\\data\\webmagic"))
//开启5个线程同时执行
.thread(5)
//启动爬虫
.run();
}
WebMagic默认提供了“输出到控制台”和“保存到文件”两种结果处理方案。WebMagic用于保存结果的组件叫做Pipeline
。通过“控制台输出结果”这件事也是通过一个内置的Pipeline完成的,它叫做ConsolePipeline
。那么,我现在想要把结果用Json的格式保存下来,怎么做呢?我只需要将Pipeline的实现换成"JsonFilePipeline"就可以了。
.addPipeline(new FilePipeline("/data/edu1"))设置爬取结果存储形式和位置,保存位置是/data/edu1。
.addPipeline(new ConsolePipeline()) 设置爬取结果存储形式和位置,这里将结果同时输出到console页面。
.setScheduler(new FileCacheQueueScheduler()) 使用文件保存抓取的URL,可以在关闭程序并下次启动时,从之前抓取的URL继续抓取。需指定路径,会建立.urls.txt和.cursor.txt两个文件。
WebMagic里主要使用了三种抽取技术:XPath、正则表达式和CSS选择器。
**抽取结果的api
//获取整个html
page.putField("download", page.getHtml().toString());
//获取第一个a链接的地址
page.putField("download", page.getHtml().links().toString());
//获取所有a链接的地址,在links后面也可以加上正则
page.putField("download", page.getHtml().links().all().toString());
//获取当前请求的url.
page.getUrl
//**正则 (https://www.runoob.com/regexp/regexp-metachar.html)
page.putField("download", page.getHtml().regex("https://bss.csdn.net/cview/reg/.*").toString());
//***xpath (https://www.w3school.com.cn/xpath/xpath_syntax.asp)
//获取类选择器叫lt_avatar的div
page.putField("download", page.getHtml().xpath("//div[@class='lt_avatar']"));
//获取类选择器叫lt_avatar的div下的img
page.putField("download", page.getHtml().xpath("//div[@class='lt_avatar']/img"));
//获取img中src属性
page.putField("download", page.getHtml().xpath("//div[@class='lt_avatar']/img/@src"));
//text()获取元素a中的文本值,在pipeline中entry.getValue()没有值
page.putField("download", page.getHtml().xpath("//div[@class='lt_avatar']/a/text()"))
//tidyText()获取元素a中的文本值,在pipeline中entry.getValue()会解析出href的链接
page.putField("download", page.getHtml().xpath("//div[@class='lt_avatar']/a/tidyText()"));
//***css,这里的lt_avatar就是属性值,格式:直接元素加属性值,子元素直接写在后面.
page.putField("download", page.getHtml().css("div.lt_avatar a"));
//这里后面的text表示获取a链接的文本值
page.putField("download", page.getHtml().css("div.lt_avatar a","text"));
//后面的href表示获取a链接的href属性值
page.putField("download", page.getHtml().css("div.lt_avatar a","href"));
//***选择器
Elements mainElements = page.getHtml().getDocument()
.getElementsByClass("lt-dialog__title");
String t=mainElements.text();
String attr= mainElements.text.attr("src");//获取元素属性值
System.out.println(t);
//获取当前元素
String html = mainElements(0).html();
List all = new Html(html)
.xpath("//div[@class=\"mod_relations\"]").links().all();
// 加入到爬虫队列
page.addTargetRequests(all);
**获取结果的api
get() 返回一条String类型的结果 String link= html.links().get()
toString() 功能同get(),返回一条String类型的结果 String link= html.links().toString()
all() 返回所有抽取结果 List links= html.links().all()
match() 是否有匹配结果 if (html.links().match()){ xxx; }
**site的相关配置
private String domain;//主机域名
private String userAgent;//http协议中的UserAgent
private MapdefaultCookies =new LinkedHashMap();//默认cookie
private Mapcookies =new HashMap>();//cookie
private String charset;//编码格式
private int sleepTime =5000;//休眠时间
private int retryTimes =0;//重试时间
private int cycleRetryTimes =0;//重试此时
private int retrySleepTime =1000;//重试休眠时间
private int timeOut =5000;//默认关闭时间
private static final SetDEFAULT_STATUS_CODE_SET =new HashSet();//状态码集合
private Set acceptStatCode =DEFAULT_STATUS_CODE_SET;//默认成功的网页返回码
private Mapheaders =new HashMap();//http协议
private boolean useGzip =true;//默认使用zip解码
private boolean disableCookieManagement =false;//需不需要使用cookie管理者
***简单实例
***pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.9.RELEASE
com.easy
webmagic
0.0.1
webmagic
Demo project for Spring Boot
1.8
UTF-8
UTF-8
UTF-8
us.codecraft
webmagic-core
0.7.3
org.slf4j
slf4j-log4j12
us.codecraft
webmagic-extension
0.7.3
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
compile
org.apache.maven.plugins
maven-compiler-plugin
1.8
**
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import us.codecraft.webmagic.Spider;
@SpringBootApplication
public class WebmagicdemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebmagicdemoApplication.class, args);
//获取影片标题和页面链接
// Spider.create(new ListPageProcesser()).addUrl("https://me.csdn.net/u011146511")
// .addPipeline(new MyPipeline()).thread(1).run();
//
//获取指定详情页面的影片下载地址
Spider.create(new DetailPageProcesser()).addUrl("https://me.csdn.net/u011146511")
.addPipeline(new MyPipeline()).thread(1).run();
}
}
**
import org.jsoup.select.Elements;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.processor.PageProcessor;
public class DetailPageProcesser implements PageProcessor {
private Site site = Site.me().setDomain("my.csdn.net");
@Override
public void process(Page page) {
// page.putField("download", page.getHtml().links().all().toString());
//正则
// page.putField("download", page.getHtml().regex("https://bss.csdn.net/cview/reg/.*").toString());
// //选择器
// Elements mainElements = page.getHtml().getDocument()
// .getElementsByClass("lt-dialog__title");
// String t=mainElements.text();
// System.out.println(t);
//xpath
// page.putField("download", page.getHtml().xpath("//div[@class='lt_avatar']"));
//css
page.putField("download", page.getHtml().css("div.lt_avatar a","href"));
}
@Override
public Site getSite() {
return site;
}
}
**
import lombok.extern.slf4j.Slf4j;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;
import java.util.Map;
@Slf4j
public class MyPipeline implements Pipeline {
@Override
public void process(ResultItems resultItems, Task task) {
log.info("get page: " + resultItems.getRequest().getUrl());
for (Map.Entry entry : resultItems.getAll().entrySet()) {
/* ResultItems 保存了抽取结果,它是一个 Map 结构,
*在 page.putField(key,value)中保存的数据,可以通过 ResultItems.get(key)获取,这个key就是之前putFile中的key ,
*getvalve就是解析获取的结果,这个结果就是putFile中value解析后的结果.
*/
log.info("解析的结果"+entry.getKey() + ":\t" + entry.getValue());
}
}
}
除了使用 page.addTargetRequests(url或者url集合) 加入到爬虫队列.
还可以使用request模拟post请求添加到爬虫队列.
Request req = new Request();
req.setMethod(HttpConstant.Method.POST);
req.setUrl("my.csdn.net");
req.setRequestBody(HttpRequestBody.json("{CategoryType: 'SiteHome', ParentCategoryId: 0, CategoryId: 808, PageIndex: " + pageNum
+ ", TotalPostCount: 4000,ItemListActionName:'PostList'}", "utf-8"));
page.addTargetRequest(req);
**WebCollector爬虫系统:https://github.com/CrawlScript/WebCollector
教程:https://www.oschina.net/p/webcollector
多种情况教程:http://datahref.com/archives/10
获取网站图片
@SpringBootApplication
//@ComponentScan("com.example.service")
public class DemoApplication {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(DemoApplication.class);
logger.info("Hello World");
/**
* ZhihuCrawler 构造器中会进行 数据初始化,这两个参数接着会传给父类
* super(crawlPath, autoParse);
* crawlPath:表示设置保存爬取记录的文件夹,本例运行之后会在应用根目录下生成一个 "crawl" 目录存放爬取信息
* */
ZhihuCrawler crawler = new ZhihuCrawler("crawl", true);
//设置为断点爬取,否则每次开启爬虫都会重新爬取
crawler.setResumable(true);
/**
* 启动爬虫,爬取的深度为4层
* 添加的第一层种子链接,为第1层
*/
try {
crawler.start(4);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
***
package com.example.crawler;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.net.HttpRequest;
import cn.edu.hfut.dmic.webcollector.net.HttpResponse;
import cn.edu.hfut.dmic.webcollector.plugin.berkeley.BreadthCrawler;
import cn.edu.hfut.dmic.webcollector.util.FileUtils;
/**
* BreadthCrawler 是 WebCollector 最常用的爬取器之一
* */
public class ZhihuCrawler extends BreadthCrawler{
// 用于保存图片的文件夹
File downloadDir;
// 原子性int,用于生成图片文件名
AtomicInteger imageId;
private final static String downPath = "/Users/HaokeMaster/Desktop/sts/jianshuImage";
public ZhihuCrawler(String crawlPath, boolean autoParse) {
super(crawlPath, autoParse);
//只有在autoParse和autoDetectImg都为true的情况下
//爬虫才会自动解析图片链接
setAutoParse(true);
//如果使用默认的Requester,需要像下面这样设置一下网页大小上限
//否则可能会获得一个不完整的页面
//下面这行将页面大小上限设置为10M
//getConf().setMaxReceiveSize(1024 * 1024 * 10);
/**设置爬取的网站地址
* addSeed 表示添加种子
* 种子链接会在爬虫启动之前加入到抓取信息中并标记为未抓取状态.这个过程称为注入*/
//添加种子URL
addSeed("http://www.meishij.net/");
//限定爬取范围
addRegex("http://www.meishij.net/.*");
addRegex("http://images.meishij.net/.*");
addRegex("-.*#.*");
addRegex("-.*\\?.*");
this.addSeed("https://www.meishij.net");
/**
* 循环添加了4个种子,其实就是分页,结果类似:
* https://blog.github.com/page/2/
* https://blog.github.com/page/3/
* https://blog.github.com/page/4/
* https://blog.github.com/page/5/
*/
// for (int pageIndex = 2; pageIndex <= 5; pageIndex++) {
// String seedUrl = String.format("https://blog.github.com/page/%d/", pageIndex);
// this.addSeed(seedUrl);
// }
/**限定爬取范围 addRegex 参数为一个 url 正则表达式, 可以用于过滤不必抓取的链接,如 .js .jpg .css ... 等
* 也可以指定抓取某些规则的链接,如下 addRegex 中会抓取 此类地址:
* https://blog.github.com/2018-07-13-graphql-for-octokit/
* */
// this.addRegex("https://blog.github.com/[0-9]{4}-[0-9]{2}-[0-9]{2}-[^/]+/");
/**
* 过滤 jpg|png|gif 等图片地址 时:
* this.addRegex("-.*\\.(jpg|png|gif).*");
* 过滤 链接值为 "#" 的地址时:
* this.addRegex("-.*#.*");
*/
/**设置线程数*/
setThreads(50);
setTopN(100);
/**
* 是否进行断电爬取,默认为 false
* setResumable(true);
*/
}
/**
* 必须重写 visit 方法,作用是:
* 在整个抓取过程中,只要抓到符合要求的页面,webCollector 就会回调该方法,并传入一个包含了页面所有信息的 page 对象
*
* @param page
* @param next
*/
@Override
public void visit(Page page, CrawlDatums next) {
downloadDir = new File(downPath);
if (!downloadDir.exists()) {
downloadDir.mkdirs();
}
computeImageId();
String url = page.url();
/**如果此页面地址 确实是要求爬取网址,则进行取值
*/
// if (page.matchUrl("http://www.meishij.net/")) {
/**
* 通过 选择器 获取页面 标题以及 正文内容
* */
// String title = page.select(".foot p").text();
// Elements content = page.select("html");
//我们需要网页中标签的属性来进行判断,只有html属性和图片属性的标签才有可能是图片标签
String contentType = page.response().contentType();
System.out.println("contentType:\n" + contentType);
if (contentType == null) {
return;
} else if (contentType.contains("html")) {
// 如果是网页,则抽取其中包含图片的URL,放入后续任务
Elements imgs = page.select("img[src]");
for (Element img : imgs) {
String imgSrc = img.attr("abs:src");
next.add(imgSrc);
}
} else if (contentType.startsWith("image")) {
// 如果是图片,直接下载
String extensionName = contentType.split("/")[1];
String imageFileName = imageId.incrementAndGet() + "." + extensionName;
File imageFile = new File(downloadDir, imageFileName);
try {
byte[] image = page.content();//图片数据
FileUtils.write(imageFile, image);
System.out.println("保存图片 " + page.url() + " 到 " + imageFile.getAbsolutePath());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
// System.out.println("URL:\n" + url);
// System.out.println("title:\n" + title);
// System.out.println("content:\n" + content);
// }
}
public void computeImageId() {
int maxId = -1;
for (File imageFile : downloadDir.listFiles()) {
String fileName = imageFile.getName();
String idStr = fileName.split("\\.")[0];
int id = Integer.valueOf(idStr);
if (id > maxId) {
maxId = id;
}
}
imageId = new AtomicInteger(maxId);
}
//设置代理userAgent,需要重写getResponse
@Override
public HttpResponse getResponse(CrawlDatum crawlDatum) throws Exception {
/* 设置代理服务器 */
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8889));
//HttpRequest hr = new HttpRequest(crawlDatum, proxy);
HttpRequest hr = new HttpRequest(crawlDatum, null);
// hr.setProxy(proxy);
hr.setUserAgent(getusergent());
return hr.response();
}
private static String[] agentarray = { "Mozilla/5.0 (compatible, MSIE 10.0, Windows NT, DigExt)",
"Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, 360SE)",
"Mozilla/4.0 (compatible, MSIE 8.0, Windows NT 6.0, Trident/4.0)",
"Mozilla/5.0 (compatible, MSIE 9.0, Windows NT 6.1, Trident/5.0),",
"Opera/9.80 (Windows NT 6.1, U, en) Presto/2.8.131 Version/11.11",
"Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, TencentTraveler 4.0)",
"Mozilla/5.0 (Windows, U, Windows NT 6.1, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Macintosh, Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
"Mozilla/5.0 (Macintosh, U, Intel Mac OS X 10_6_8, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Linux, U, Android 3.0, en-us, Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",
"Mozilla/5.0 (iPad, U, CPU OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
"Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, Trident/4.0, SE 2.X MetaSr 1.0, SE 2.X MetaSr 1.0, .NET CLR 2.0.50727, SE 2.X MetaSr 1.0)",
"Mozilla/5.0 (iPhone, U, CPU iPhone OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
"MQQBrowser/26 Mozilla/5.0 (Linux, U, Android 2.3.7, zh-cn, MB200 Build/GRJ22, CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"
};
public static String getusergent() {
Random rand = new Random();
return agentarray[rand.nextInt(agentarray.length)];
}
}
https://blog.csdn.net/jiangsanfeng1111/article/details/52334907
爬取js相关:https://blog.csdn.net/osaymissyou0/article/details/49450209、https://blog.csdn.net/osaymissyou0/article/details/49450209
webcollector地址:https://github.com/CrawlScript/WebCollector/blob/master/README.md