大家都知道,想要爬取某宝的商品,如果只是用HttpURLConnection发个请求,失败率是很高的。一般想要保证成功率的话,都会选择真实的浏览器去抓取。
以前常用的解决方案是selenium或phantomjs,但是它两的环境配置太麻烦了,对程序员极度不友好,自从谷歌推出Puppeteer后,puppeteer迅速流行起来,获得大家一致称赞。它是一个NodeJS库,但今天并不是要使用它来爬取某宝商品,而是使用Java语言写的Jvppeteer,Jvppeteer与Puppeteer是同样的实现原理。
思路:1.启动
//指定启动路径,启动浏览器
String path = new String("F:\\java教程\\49期\\vuejs\\puppeteer\\.local-chromium\\win64-722234\\chrome-win\\chrome.exe".getBytes(), "UTF-8");
ArrayList<String> argList = new ArrayList<>();
LaunchOptions options = new Optionsbuilder().withArgs(argList).withHeadless(false).withExecutablePath(path).build();
argList.add("--no-sandbox");
argList.add("--disable-setuid-sandbox");
Browser browser = Puppeteer.launch(options);
2.page队列
//启动一个线程池多线程抓取
int threadCount = 5;
ThreadPoolexecutor executor = new ThreadPoolExecutor(threadCount, threadCount, 30, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
CompletionService service = new ExecutorCompletionService(executor);
//打开5个页面同时抓取,这些页面可以多次利用,这样减少创建网页带来的性能消耗
LinkedBlockingQueue<Page> pages = new LinkedBlockingQueue<>();
for (int i = 0; i < threadCount; i ) {
Page page = browser.newPage();
//拦截请求,可选
// page.onrequest(request -> {
// if ("image".equals(request.resourceType()) || "media".equals(request.resourceType())) {
// //遇到多媒体或者图片资源请求,拒绝,加载页面加载
// request.abort();
// } else {//其他资源放行
// request.continueRequest();
// }
// });
// page.setRequestInterception(true);
pages.put(page);//往队列后面放,阻塞
}
3.定义爬取线程
static class CrawlerCallable implements Callable<Object> {
private LinkedBlockingQueue<Page> pages;
public CrawlerCallable(LinkedBlockingQueue<Page> pages) {
this.pages = pages;
}
@Override
public Object call() {
Page page = null;
try {
page = pages.take();
PageNavigateOptions navigateOptions = new PageNavigateOptions();
navigateOptions.setWaitUntil(Arrays.asList("domcontentloaded"));
System.out.println("gotothreadName:" Thread.currentThread().getName());
page.goTo("https://item.taobao.com/item.htm?id=541605195654", navigateOptions);
String content = page.content();
//解析商品
return parseItem(content);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (page != null) {
try {
pages.put(page);//把已经抓取完的网页放回队列里
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return null;
}
}
4.关闭线程池,获取结果
//结果集
List<future<Object>> futures = new ArrayList<>();
//抓取100次
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i ) {
Future<Object> future = service.submit(new CrawlerCallable(pages));
futures.add(future);
}
//关闭线程池
executor.shutdown();
//获取结果
int i = 0;
for (Future<Object> result : futures) {
Object item = result.get();
i ;
System.out.println(i ":" Constant.OBJECTMAPPER.writeValueAsString(item));
}
long end = System.currentTimeMillis();
System.out.println("时间:" (end - start));
在俺电脑测试,100个爬取任务只需要15s,速度还是非常的快。速度的快慢受到根据电配置以及带宽的影响,配置越好,速度越快。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved