刚刚开始学,很多东西可能理解错了,还请各位指教
一些基本类:
Request:包含要爬行的url和一些附加信息,是Page的一个成员变量
主要成员变量
String url
Map<String, Object> extras 存储附加信息
long priority 优先级 值越大越优先
主要方法
Request(String url) { this.url = url; }构造函数
Request setPriority(long priority) 设置优先级需要PriorityScheduler管理
Object getExtra(String key)获取想要的附加信息 通过key在map里寻找
Request putExtra(String key, Object value) 添加一组附加信息
ResultItems:包含抓取的结果,是Page类的一个成员变量,并且要在pipeline中处理
主要成员变量
Map<String, Object> fields 是HashMap
Request request;
boolean skip 是否要跳过这条结果,跳过了就不会被pipeline处理
主要方法
<T> T get(String key) 通过key获取相应值
Map<String, Object> getAll() { return fields; }
ResultItems put(String key, T value) 给当前对象添加一对值就是field添加记录
Request getRequest() { return request; }
Page:包含页面抽取的结果和要去取的URL
主要成员变量
Request request; 主要就是url对象
ResultItems resultItems 抓取的结果,用于持久化
Html html;
String rawText;
Selectable url;
Int statusCode;
List<Request> targetRequests
主要方法
Selectable getUrl(){ return url; } 获取当前页url
Html getHtml()获取当前页内容
ResultItems getResultItems(){return resultItems; }获得抓取的结果以在Pipeline持久化里使用
void putField(String, Object)保存抓取的结果
void addTargetRequests(List<String> requests) 添加url 去抓取
void addTargetRequests(List<String> requests, long priority) 添加url 去抓取
void addTargetRequest(String requestString) 添加url 去抓取
void addTargetRequest(Request request) 添加request 去抓取
Site:包含爬虫的一些配置
主要成员变量
String domain;
List<Request> startRequests = new ArrayList<Request>(); 爬虫开始的url集
Map<String, String> cookies = new LinkedHashMap<String, String>();
Map<String, String> headers = new HashMap<String, String>()
String userAgent;
String charset;
int sleepTime = 5000;
int retryTimes = 0;
int cycleRetryTimes = 0;
int timeOut = 5000;
HttpHost httpProxy
主要方法
Site me() { return new Site(); } 新生成一个Site
Site addCookie(String name, String value) 说明Add a cookie with domain
Site setDomain(String domain) 设置Site的domain
Site addStartRequest(Request startRequest) 添加一条url到开始集里
Site addHeader(String key, String value) 为下载器设置一个http头
Task toTask()转换为一个Task
Task:标识不同任务的接口(是个interface),没有成员变量
主要方法
String getUUID() 获取一个task的唯一ID
Site getSite() 获取一个task的Site
Spider:爬虫入口,包含Downloader Scheduler PageProcessor and Pipeline
主要成员变量
Downloader downloader;
List<Pipeline> pipelines = new ArrayList<Pipeline>();
Scheduler scheduler = new QueueScheduler();
PageProcessor pageProcessor;
List<Request> startRequests;
Site site;
String uuid;
Logger logger = Logger.getLogger(getClass());
int threadNum = 1;
主要方法
Spider create(PageProcessor pageProcessor) 创建一个爬虫
Spider startUrls(List<String> startUrls)添加开始集合 也就是给startRequests赋值
Spider startRequest(List<Request> startRequests) 添加开始集合,给startRequests赋值
Spider scheduler(Scheduler scheduler) 设置scheduler(url管理器),给scheduler赋值
Spider setScheduler(Scheduler scheduler) 设置scheduler(url管理器) ,给scheduler赋值
Spider pipeline(Pipeline pipeline) 设置pipeline(持久化),给pipelines队列添加一条
Spider addPipeline(Pipeline pipeline) 设置pipeline(持久化),给pipelines队列添加一条
Spider clearPipeline() 清空pipeline
Spider downloader(Downloader downloader) 设置downloader(下载器),给downloader赋值
Spider setDownloader(Downloader downloader)设置downloader,给downloader赋值
void test(String... urls) 该方法只抓取一个单独的页面,用于测试抽取效果
void processRequest(Request request){ //核心处理流程
Page page = downloader.download(request, this);
pageProcessor.process(page);
extractAndAddRequests(page);
for (Pipeline pipeline : pipelines)
pipeline.process(page.getResultItems(), this);
}
一个简单例子
Spider.create(new SimplePageProcessor("http://my.oschina.net/",
"http://my.oschina.net/*blog/*")).run()
如果想把结果存到文件里怎么办呢?
Spider.create(new SimplePageProcessor("http://my.oschina.net/",
"http://my.oschina.net/*blog/*")) .pipeline(new FilePipeline("/data/temp/webmagic/")).run();
使用FileCacheQueueScheduler在文件中存取url和游标以便关闭后重新继续开始
Spider.create(new SimplePageProcessor("http://my.oschina.net/",
"http://my.oschina.net/*blog/*"))
.scheduler(new FileCacheQueueScheduler("/data/temp/webmagic/cache/")).run();
webmagic四大模块代码解析
downloader文件件夹 ,download一般不用管
Downloader是一个接口
主要方法
Page download(Request request, Task task);下载页面并存到Page对象
void setThread(int threadNum); 设置线程数
HttpClientDownloader 继承Downloader接口
主要成员变量
Logger logger = Logger.getLogger(getClass());
Map<String, CloseableHttpClient> httpClients = new HashMap<String, CloseableHttpClient>();
HttpClientGenerator httpClientGenerator = new HttpClientGenerator();
主要方法
Html download(String url) 下载html
Html download(String url, String charset)
Page download(Request request, Task task) 实现接口方法
HttpClientGenerator 这个类是HttpClient产生器,就是工厂
主要成员变量
PoolingHttpClientConnectionManager connectionManager;
主要方法
CloseableHttpClient generateClient(Site site)
CloseableHttpClient getClient(Site site)
HttpClientGenerator setPoolSize(int poolSize)
void generateCookie(HttpClientBuilder httpClientBuilder, Site site)
目前有几个Downloader的实现:
HttpClientDownloader
集成了Apache HttpClient的Downloader。Apache HttpClient(4.0后整合到HttpCompenent项目中)是强大的Java http下载器,它支持自定义HTTP头(对于爬虫比较有用的就是User-agent、cookie等)、自动redirect、连接复用、cookie保留、设置代理等诸多强大的功能。
SeleniumDownloader(这个文件里没有)
对于一些Javascript动态加载的网页,仅仅使用http模拟下载工具,并不能取到页面的内容。这方面的思路有两种:一种是抽丝剥茧,分析js的逻辑,再用爬虫去重现它;另一种就是:内置一个浏览器,直接获取最后加载完的页面。webmagic-selenium包中整合了Selenium到SeleniumDownloader,可以直接进行动态载页面的抓取。使用selenium需要安装一些native的工具,具体步骤可以参考作者的博文使用Selenium来抓取动态加载的页面
PageProcessor文件夹,页面分析及链接抽取,是我们使用的关键
PageProcessor是一个接口,用于定制爬虫,可定制启动url和一些设置,如何发现要抓取的url,数据要如何提取和存储
主要方法
void process(Page page); 处理Page对象,提取URL,提取数据并存储
Site getSite() 获取site 的一些设置信息
通过编写一个实现PageProcessor接口的类,就可以定制一个自己的爬虫,比如
public class GithubRepoPageProcesser implements PageProcessor {
private Site site = Site.me().setRetryTimes(3).setSleepTime(100); //一些设置信息
@Override
public void process(Page page) { //通过正则表达式和Xpath来抓取
//要抓取的链接需要显示地添加
page.addTargetRequests(page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all());
//抓取规则
page.putField("author", page.getUrl().regex("https://github\\.com/(\\w+)/.*").toString());
page.putField("name", page.getHtml().xpath("//h1[@class='entry-title public']/strong/a/text()").toString());
if (page.getResultItems().get("name")==null){ page.setSkip(true); } //skip this page
page.putField("readme", page.getHtml().xpath("//div[@id='readme']/tidyText()"));
}
@Override
public Site getSite() {
return site;
}
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcesser()).addUrl("https://github.com/code4craft").thread(5).run();
}
}
几种抓取方式
1.java正则表达式:这个不多讲 . [] () 等
2.Jsoup支持jquery中css selector的方式选取元素 :
String content = "blabla"; Document doc = JSoup.parse(content); Elements links = doc.select("a[href]");
3. HtmlCleaner支持XPath的方式选取元素:
4.Xpath: tagNode.evaluateXPath("//a/@href ")
5.CSS选择:$("a[href]").attr("href")
webmagic主要实现了CSS Selector、XPath和正则表达式三种抓取方式,其实现放在Selector文件下
Scheduler文件夹,URL管理 主要有两个实现QueueScheduler和FileCacheQueueScheduler
Scheduler是一个接口,实现它可以管理要抓取的URL,还可以去重复
主要方法
void push(Request request, Task task) 添加一个要抓取的url
Request poll(Task task) 取出一个URL来爬行
QueueScheduler继承Scheduler接口,一个简单的内存队列,速度较快,并且是线程安全的
主要成员变量
Logger logger = Logger.getLogger(getClass());
BlockingQueue<Request> queue = new LinkedBlockingQueue<Request>();
Set<String> urls = new HashSet<String>();
主要方法
void push(Request request, Task task) 往queue里边添加一个request
Request poll(Task task) 从queue里边弹出一个request
PriorityScheduler继承Scheduler接口,是一个文件队列,它可以用于耗时较长的下载任务,在任务中途停止后,下次执行仍然从中止的URL开始继续爬取。
主要成员变量
Logger logger = Logger.getLogger(getClass());
BlockingQueue<Request> noPriorityQueue = new LinkedBlockingQueue<Request>();
Set<String> urls = new HashSet<String>();
主要方法
void push(Request request, Task task) 添加一个request
Request poll(Task task) 弹出一个request
Pipeline文件夹,用于后续处理和持久化 主要有四个实现
Pipeline是一个接口,用于持久化 和 离线处理 只有一个方法
主要方法
void process(ResultItems resultItems, Task task) 从resultItems通过get(key)得到数据
CollectorPipeline<T>也是一个接口,且继承了Pipeline,新增了一个方法
主要方法
List<T> getCollected(); 获取收集到的所有信息
ConsolePipeline 实现了Pipeline接口,把结果输出到控制台
public void process(ResultItems resultItems, Task task) {
System.out.println("get page: " + resultItems.getRequest().getUrl());
for (Map.Entry<String, Object> entry : resultItems.getAll().entrySet()) {
System.out.println(entry.getKey() + ":\t" + entry.getValue());
}
}
ResultItemsCollectorPipeline实现了CollectorPipeline<T>接口
主要成员变量
List<ResultItems> collector = new ArrayList<ResultItems>();
主要方法
public synchronized void process(ResultItems resultItems, Task task) {
collector.add(resultItems);
}
public List<ResultItems> getCollected() {
return collector;
}
FilePipeline 实现了FilePersistentBase,Pipeline接口,把数据存到文件里,每个URL单独保存到一个页面,以URL的MD5结果作为文件名
主要成员变量
Logger logger = Logger.getLogger(getClass());
主要方法
FilePipeline() { setPath("/data/webmagic/"); } 默认构造函数 设置了存储路径
FilePipeline(String path) { setPath(path); } 自定义存储路径
void process(ResultItems resultItems, Task task)
selector文件夹,算是PageProcessor的扩展吧,因为要集合很多选取方式
Selectable:接口 可选的文本
Selectable xpath(String xpath);使用xpath选择
Selectable $(String selector); 使用CSS选择
Selectable $(String selector, String attrName); 使用CSS选择
Selectable css(String selector); 使用CSS选择
Selectable css(String selector, String attrName); 使用CSS选择
Selectable regex(String regex);使用正则表达式选择group默认为1
Selectable regex(String regex, int group); 使用正则表达式选择
Selectable replace(String regex, String replacement);
Selectable smartContent(); 选取smart content
Selectable links(); 选取所有链接
PlainText:实现了Selectable接口
PlainText(List<String> strings)
PlainText(String text)
PlainText create(String text)
Selectable select(Selector selector, List<String> strings)
Selectable selectList(Selector selector, List<String> strings)
Html:继承了PlainText
主要成员变量
Logger logger = Logger.getLogger(getClass());
Document document; 存储解析过的文档
boolean init = false;
主要方法:给出新增的方法
Html(List<String> strings)
Html(String text)
Html(Document document)
void initDocument() 简单的初始化方法
Html create(String text)
String selectDocument(Selector selector)
List<String> selectDocumentForList(Selector selector)
String getText()
Document getDocument()
Selectors:一个抽象类
RegexSelector regex(String expr) RegexSelector regex(String expr, int group)
CssSelector $(String expr) CssSelector $(String expr, String attrName)
XpathSelector xpath(String expr) XsoupSelector xsoup(String expr)
AndSelector and(Selector... selectors) OrSelector or(Selector... selectors)
SmartContentSelector smartContent()
Selector:接口,文本抽取器 就两个方法
String select(String text) 抽取单条结果,若有多个,只有第一个被选择
List<String> selectList(String text) 抽取所有结果
ElementSelector:接口 针对html elements
String select(Element element);
List<String> selectList(Element element);
RegexSelector:实现Selector接口,使用正则表达式抽取
主要成员变量
String regexStr;
Pattern regex;
int group = 1;
主要方法
RegexSelector(String regexStr, int group)构造
RegexSelector(String regexStr)构造
String select(String text)重写
List<String> selectList(String text)重写
RegexResult selectGroup(String text)
List<RegexResult> selectGroupList(String text)
XpathSelector:实现Selector接口,使用Xpath抽取
主要成员变量
String xpathStr;
主要成员方法
XpathSelector(String xpathStr)
String select(String text)重写
List<String> selectList(String text)重写
ReplaceSelector:实现Selector接口,重置选择器
主要成员变量
String regexStr;
String replacement;
Pattern regex;
主要成员方法
ReplaceSelector(String regexStr, String replacement)
String select(String text)重写
List<String> selectList(String text)重写
AndSelector:实现Selector接口,所有选择器以管道式安排,后一个用前一个的结果
主要成员变量
List<Selector> selectors = new ArrayList<Selector>()
主要成员方法
AndSelector(Selector... selectors)
AndSelector(List<Selector> selectors)
String select(String text)重写
List<String> selectList(String text)重写
OrSelector:实现Selector接口,所有提取器独自工作,提取的结果将会整合起来
主要成员变量
List<Selector> selectors = new ArrayList<Selector>()
主要成员方法
OrSelector(Selector... selectors)
OrSelector(List<Selector> selectors)
String select(String text)重写
List<String> selectList(String text)重写
OrSelector:实现Selector接口,所有提取器独自工作,提取的结果将会整合起来
主要成员变量
List<Selector> selectors = new ArrayList<Selector>()
主要成员方法
OrSelector(Selector... selectors)
OrSelector(List<Selector> selectors)
String select(String text)重写
List<String> selectList(String text)重写
BaseElementSelector:抽象类 继承于Selector, ElementSelector
String select(String text)重写
List<String> selectList(String text)重写
CssSelector:继承BaseElementSelector CSS selector. Based on Jsoup
主要成员变量
String selectorText;
String attrName;
主要成员方法
CssSelector(String selectorText)
CssSelector(String selectorText, String attrName)
String getValue(Element element)
String select(String text)重写
List<String> selectList(String text)重写
XsoupSelector:继承BaseElementSelector XPath selector based on Xsoup
主要成员变量
XPathEvaluator xPathEvaluator;
主要成员方法
XsoupSelector(String xpathStr)
String select(String text)重写
List<String> selectList(String text)重写
例如,我已经下载了一个页面,现在要抽取某个区域的所有包含"blog"的链接,我可以这样写:
String content = "blabla"; //content是用别的爬虫工具抽取到的正文
List<String> links = Html.create(content)
.$("div.title") //css 选择,Java里虽然很少有$符号出现,不过貌似$作为方法名是合法的
.xpath("//@href") //提取链接
.regex(".*blog.*") //正则匹配过滤
.all(); //转换为string列表
utils文件夹,一些实用工具
UrlUtils:url和html的工具
Pattern patternForProtocal = Pattern.compile("[\\w]+://")
Pattern patternForCharset = Pattern.compile("charset\\s*=\\s*['\"]*([^\\s;'\"]*)");
Pattern patternForHref = Pattern.compile("(<a[^<>]*href=)[\"']{0,1}([^\"'<>\\s]*)[\"']{0,1}", Pattern.CASE_INSENSITIVE);
String canonicalizeUrl(String url, String refer)
String getHost(String url)
String removeProtocol(String url)
String getDomain(String url)
String fixAllRelativeHrefs(String html, String url)
List<Request> convertToRequests(Collection<String> urls)
List<String> convertToUrls(Collection<Request> requests)
String getCharset(String contentType)
ThreadUtils:
ExecutorService newFixedThreadPool(int threadSize)
NumberUtils:抽象类
int compareLong(long o1, long o2)
FilePersistentBase:文件持久化的基本对象
String path
String PATH_SEPERATOR = "/"
String getPath()
void checkAndMakeParentDirecotry(String fullName)
File getFile(String fullName)
void setPath(String path)
EnvironmentUtil
String USE_XSOUP = "xsoup"
boolean useXsoup()
void setUseXsoup(boolean useXsoup)