使用java爬蟲WebCollector+jsoup抓取商品分類圖標

背景介紹:

場景是,有京東三級分類名稱,沒有對應圖標,需要根據京東三級分類名稱,獲取分類名稱匹配的圖片,來作為商品分類圖標

技術選型:

WebCollector+jsoup,WebCollector進行爬取,jsoup進行html解析

實現步驟:

1.根據根url發起請求,

2.得到響應頁面數據,

3.對頁面數據進行解析,并提取

4.對圖片進行下載持久化

代碼實現

1.相關包結構說明


2.代碼實例

links.java 類,存儲已經訪問過的URL路徑 和 待訪問的URL 路徑;

package com.etoak.crawl.link;

import java.util.HashSet;

import java.util.LinkedList;

import java.util.Set;

/*

*? Link主要功能;

*? 1: 存儲已經訪問過的URL路徑 和 待訪問的URL 路徑;

*

*

* */

public class Links {

? ? //已訪問的 url 集合? 已經訪問過的 主要考慮 不能再重復了 使用set來保證不重復;

? ? private static Set visitedUrlSet = new HashSet();

? ? //待訪問的 url 集合? 待訪問的主要考慮 1:規定訪問順序;2:保證不提供重復的帶訪問地址;

? ? private static LinkedList unVisitedUrlQueue = new LinkedList();

? ? //獲得已經訪問的 URL 數目

? ? public static int getVisitedUrlNum() {

? ? ? ? return visitedUrlSet.size();

? ? }

? ? //添加到訪問過的 URL

? ? public static void addVisitedUrlSet(String url) {

? ? ? ? visitedUrlSet.add(url);

? ? }

? ? //移除訪問過的 URL

? ? public static void removeVisitedUrlSet(String url) {

? ? ? ? visitedUrlSet.remove(url);

? ? }

? ? //獲得 待訪問的 url 集合

? ? public static LinkedList getUnVisitedUrlQueue() {

? ? ? ? return unVisitedUrlQueue;

? ? }

? ? // 添加到待訪問的集合中? 保證每個 URL 只被訪問一次

? ? public static void addUnvisitedUrlQueue(String url) {

? ? ? ? if (url != null && !url.trim().equals("")? && !visitedUrlSet.contains(url)? && !unVisitedUrlQueue.contains(url)){

? ? ? ? ? ? unVisitedUrlQueue.add(url);

? ? ? ? }

? ? }

? ? //刪除 待訪問的url

? ? public static Object removeHeadOfUnVisitedUrlQueue() {

? ? ? ? return unVisitedUrlQueue.removeFirst();

? ? }

? ? //判斷未訪問的 URL 隊列中是否為空

? ? public static boolean unVisitedUrlQueueIsEmpty() {

? ? ? ? return unVisitedUrlQueue.isEmpty();

? ? }

}

Page.java類,保存獲取到的響應的相關內容;

package com.etoak.crawl.page;

import com.etoak.crawl.util.CharsetDetector;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import java.io.UnsupportedEncodingException;

/*

* page

*? 1: 保存獲取到的響應的相關內容;

* */

public class Page {

? ? private byte[] content ;

? ? private String html ;? //網頁源碼字符串

? ? private Document doc? ;//網頁Dom文檔

? ? private String charset ;//字符編碼

? ? private String url ;//url路徑

? ? private String contentType ;// 內容類型

? ? public Page(byte[] content , String url , String contentType){

? ? ? ? this.content = content ;

? ? ? ? this.url = url ;

? ? ? ? this.contentType = contentType ;

? ? }

? ? public String getCharset() {

? ? ? ? return charset;

? ? }

? ? public String getUrl(){return url ;}

? ? public String getContentType(){ return contentType ;}

? ? public byte[] getContent(){ return content ;}

? ? /**

? ? * 返回網頁的源碼字符串

? ? *

? ? * @return 網頁的源碼字符串

? ? */

? ? public String getHtml() {

? ? ? ? if (html != null) {

? ? ? ? ? ? return html;

? ? ? ? }

? ? ? ? if (content == null) {

? ? ? ? ? ? return null;

? ? ? ? }

? ? ? ? if(charset==null){

? ? ? ? ? ? charset = CharsetDetector.guessEncoding(content); // 根據內容來猜測 字符編碼

? ? ? ? }

? ? ? ? try {

? ? ? ? ? ? this.html = new String(content, charset);

? ? ? ? ? ? return html;

? ? ? ? } catch (UnsupportedEncodingException ex) {

? ? ? ? ? ? ex.printStackTrace();

? ? ? ? ? ? return null;

? ? ? ? }

? ? }

? ? /*

? ? *? 得到文檔

? ? * */

? ? public Document getDoc(){

? ? ? ? if (doc != null) {

? ? ? ? ? ? return doc;

? ? ? ? }

? ? ? ? try {

? ? ? ? ? ? this.doc = Jsoup.parse(getHtml(), url);

? ? ? ? ? ? return doc;

? ? ? ? } catch (Exception ex) {

? ? ? ? ? ? ex.printStackTrace();

? ? ? ? ? ? return null;

? ? ? ? }

? ? }

}



PageParserTool.java 類,處理html頁面

package com.etoak.crawl.page;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.Iterator;

import java.util.Set;

public class PageParserTool {

? ? /* 通過選擇器來選取頁面的 */

? ? public static Elements select(Page page , String cssSelector) {

? ? ? ? return page.getDoc().select(cssSelector);

? ? }

? ? /*

? ? *? 通過css選擇器來得到指定元素;

? ? *

? ? *? */

? ? public static Element select(Page page , String cssSelector, int index) {

? ? ? ? Elements eles = select(page , cssSelector);

? ? ? ? int realIndex = index;

? ? ? ? if (index < 0) {

? ? ? ? ? ? realIndex = eles.size() + index;

? ? ? ? }

? ? ? ? return eles.get(realIndex);

? ? }

? ? /**

? ? * 獲取滿足選擇器的元素中的鏈接 選擇器cssSelector必須定位到具體的超鏈接

? ? * 例如我們想抽取id為content的div中的所有超鏈接,這里

? ? * 就要將cssSelector定義為div[id=content] a

? ? *? 放入set 中 防止重復;

? ? * @param cssSelector

? ? * @return

? ? */

? ? public static? Set<String> getLinks(Page page ,String cssSelector) {

? ? ? ? Set<String> links? = new HashSet<String>() ;

? ? ? ? Elements es = select(page , cssSelector);

? ? ? ? Iterator iterator? = es.iterator();

? ? ? ? while(iterator.hasNext()) {

? ? ? ? ? ? Element element = (Element) iterator.next();

? ? ? ? ? ? if ( element.hasAttr("href") ) {

? ? ? ? ? ? ? ? links.add(element.attr("abs:href"));

? ? ? ? ? ? }else if( element.hasAttr("src") ){

? ? ? ? ? ? ? ? links.add(element.attr("abs:src"));

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return links;

? ? }

? ? /**

? ? * 獲取網頁中滿足指定css選擇器的所有元素的指定屬性的集合

? ? * 例如通過getAttrs("img[src]","abs:src")可獲取網頁中所有圖片的鏈接

? ? * @param cssSelector

? ? * @param attrName

? ? * @return

? ? */

? ? public static ArrayList<String> getAttrs(Page page , String cssSelector, String attrName) {

? ? ? ? ArrayList<String> result = new ArrayList<String>();

? ? ? ? Elements eles = select(page ,cssSelector);

? ? ? ? for (Element ele : eles) {

? ? ? ? ? ? if (ele.hasAttr(attrName)) {

? ? ? ? ? ? ? ? result.add(ele.attr(attrName));

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return result;

? ? }

}

RequestAndResponseTool.java 類,進行請求響應

package com.etoak.crawl.page;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.HttpException;

import org.apache.commons.httpclient.HttpStatus;

import org.apache.commons.httpclient.methods.GetMethod;

import org.apache.commons.httpclient.params.HttpMethodParams;

import java.io.IOException;

public class RequestAndResponseTool {

? ? public static Page? sendRequstAndGetResponse(String url) {

? ? ? ? Page page = null;

? ? ? ? // 1.生成 HttpClinet 對象并設置參數

? ? ? ? HttpClient httpClient = new HttpClient();

? ? ? ? // 設置 HTTP 連接超時 5s

? ? ? ? httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

? ? ? ? // 2.生成 GetMethod 對象并設置參數

? ? ? ? GetMethod getMethod = new GetMethod(url);

? ? ? ? // 設置 get 請求超時 5s

? ? ? ? getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);

? ? ? ? // 設置請求重試處理

? ? ? ? getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());

? ? ? ? // 3.執行 HTTP GET 請求

? ? ? ? try {

? ? ? ? ? ? int statusCode = httpClient.executeMethod(getMethod);

? ? ? ? // 判斷訪問的狀態碼

? ? ? ? ? ? if (statusCode != HttpStatus.SC_OK) {

? ? ? ? ? ? ? ? System.err.println("Method failed: " + getMethod.getStatusLine());

? ? ? ? ? ? }

? ? ? ? // 4.處理 HTTP 響應內容

? ? ? ? ? ? byte[] responseBody = getMethod.getResponseBody();// 讀取為字節 數組

? ? ? ? ? ? String contentType = getMethod.getResponseHeader("Content-Type").getValue(); // 得到當前返回類型

? ? ? ? ? ? page = new Page(responseBody,url,contentType); //封裝成為頁面

? ? ? ? } catch (HttpException e) {

? ? ? ? // 發生致命的異常,可能是協議不對或者返回的內容有問題

? ? ? ? ? ? System.out.println("Please check your provided http address!");

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (IOException e) {

? ? ? ? // 發生網絡異常

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? // 釋放連接

? ? ? ? ? ? getMethod.releaseConnection();

? ? ? ? }

? ? ? ? return page;

? ? }

}



CharsetDetector.java類,進行字符集處理

/*

* Copyright (C) 2014 hu

*

* This program is free software; you can redistribute it and/or

* modify it under the terms of the GNU General Public License

* as published by the Free Software Foundation; either version 2

* of the License, or (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.? See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA? 02111-1307, USA.

*/

package com.etoak.crawl.util;

import org.mozilla.universalchardet.UniversalDetector;

import java.io.UnsupportedEncodingException;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/**

* 字符集自動檢測

*

* @author hu

*/

public class CharsetDetector {

? ? //從Nutch借鑒的網頁編碼檢測代碼

? ? private static final int CHUNK_SIZE = 2000;

? ? private static Pattern metaPattern = Pattern.compile(

? ? ? ? ? ? "<meta\\s+([^>]*http-equiv=(\"|')?content-type(\"|')?[^>]*)>",

? ? ? ? ? ? Pattern.CASE_INSENSITIVE);

? ? private static Pattern charsetPattern = Pattern.compile(

? ? ? ? ? ? "charset=\\s*([a-z][_\\-0-9a-z]*)", Pattern.CASE_INSENSITIVE);

? ? private static Pattern charsetPatternHTML5 = Pattern.compile(

? ? ? ? ? ? "<meta\\s+charset\\s*=\\s*[\"']?([a-z][_\\-0-9a-z]*)[^>]*>",

? ? ? ? ? ? Pattern.CASE_INSENSITIVE);

? ? //從Nutch借鑒的網頁編碼檢測代碼

? ? private static String guessEncodingByNutch(byte[] content) {

? ? ? ? int length = Math.min(content.length, CHUNK_SIZE);

? ? ? ? String str = "";

? ? ? ? try {

? ? ? ? ? ? str = new String(content, "ascii");

? ? ? ? } catch (UnsupportedEncodingException e) {

? ? ? ? ? ? return null;

? ? ? ? }

? ? ? ? Matcher metaMatcher = metaPattern.matcher(str);

? ? ? ? String encoding = null;

? ? ? ? if (metaMatcher.find()) {

? ? ? ? ? ? Matcher charsetMatcher = charsetPattern.matcher(metaMatcher.group(1));

? ? ? ? ? ? if (charsetMatcher.find()) {

? ? ? ? ? ? ? ? encoding = new String(charsetMatcher.group(1));

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? if (encoding == null) {

? ? ? ? ? ? metaMatcher = charsetPatternHTML5.matcher(str);

? ? ? ? ? ? if (metaMatcher.find()) {

? ? ? ? ? ? ? ? encoding = new String(metaMatcher.group(1));

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? if (encoding == null) {

? ? ? ? ? ? if (length >= 3 && content[0] == (byte) 0xEF

? ? ? ? ? ? ? ? ? ? && content[1] == (byte) 0xBB && content[2] == (byte) 0xBF) {

? ? ? ? ? ? ? ? encoding = "UTF-8";

? ? ? ? ? ? } else if (length >= 2) {

? ? ? ? ? ? ? ? if (content[0] == (byte) 0xFF && content[1] == (byte) 0xFE) {

? ? ? ? ? ? ? ? ? ? encoding = "UTF-16LE";

? ? ? ? ? ? ? ? } else if (content[0] == (byte) 0xFE

? ? ? ? ? ? ? ? ? ? ? ? && content[1] == (byte) 0xFF) {

? ? ? ? ? ? ? ? ? ? encoding = "UTF-16BE";

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return encoding;

? ? }

? ? /**

? ? * 根據字節數組,猜測可能的字符集,如果檢測失敗,返回utf-8

? ? *

? ? * @param bytes 待檢測的字節數組

? ? * @return 可能的字符集,如果檢測失敗,返回utf-8

? ? */

? ? public static String guessEncodingByMozilla(byte[] bytes) {

? ? ? ? String DEFAULT_ENCODING = "UTF-8";

? ? ? ? UniversalDetector detector = new UniversalDetector(null);

? ? ? ? detector.handleData(bytes, 0, bytes.length);

? ? ? ? detector.dataEnd();

? ? ? ? String encoding = detector.getDetectedCharset();

? ? ? ? detector.reset();

? ? ? ? if (encoding == null) {

? ? ? ? ? ? encoding = DEFAULT_ENCODING;

? ? ? ? }

? ? ? ? return encoding;

? ? }

? ? /**

? ? * 根據字節數組,猜測可能的字符集,如果檢測失敗,返回utf-8

? ? * @param content 待檢測的字節數組

? ? * @return 可能的字符集,如果檢測失敗,返回utf-8

? ? */

? ? public static String guessEncoding(byte[] content) {

? ? ? ? String encoding;

? ? ? ? try {

? ? ? ? ? ? encoding = guessEncodingByNutch(content);

? ? ? ? } catch (Exception ex) {

? ? ? ? ? ? return guessEncodingByMozilla(content);

? ? ? ? }

? ? ? ? if (encoding == null) {

? ? ? ? ? ? encoding = guessEncodingByMozilla(content);

? ? ? ? ? ? return encoding;

? ? ? ? } else {

? ? ? ? ? ? return encoding;

? ? ? ? }

? ? }

}



FileTool .java本類主要是 下載那些已經訪問過的文件

package com.etoak.crawl.util;

import com.etoak.crawl.page.Page;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

/*? 本類主要是 下載那些已經訪問過的文件*/

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() {

? ? ? ? if (dirPath == null) {

? ? ? ? ? ? dirPath = Class.class.getClass().getResource("/").getPath() + "temp\\";

? ? ? ? }

? ? ? ? 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 filePath = dirPath + fileName ;

? ? ? ? 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("文件:"+ fileName + "已經被存儲在"+ filePath? );

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

}


RegexRule.java類,正則

/*

* Copyright (C) 2014 hu

*

* This program is free software; you can redistribute it and/or

* modify it under the terms of the GNU General Public License

* as published by the Free Software Foundation; either version 2

* of the License, or (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.? See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA? 02111-1307, USA.

*/

package com.etoak.crawl.util;

import java.util.ArrayList;

import java.util.regex.Pattern;

/**

*

* @author hu

*/

public class RegexRule {


? ? public RegexRule(){


? ? }

? ? public RegexRule(String rule){

? ? ? ? addRule(rule);

? ? }


? ? public RegexRule(ArrayList<String> rules){

? ? ? ? for (String rule : rules) {

? ? ? ? ? ? addRule(rule);

? ? ? ? }

? ? }


? ? public boolean isEmpty(){

? ? ? ? return positive.isEmpty();

? ? }

? ? private ArrayList<String> positive = new ArrayList<String>();

? ? private ArrayList<String> negative = new ArrayList<String>();



? ? /**

? ? * 添加一個正則規則 正則規則有兩種,正正則和反正則

? ? * URL符合正則規則需要滿足下面條件: 1.至少能匹配一條正正則 2.不能和任何反正則匹配

? ? * 正正則示例:+a.*c是一條正正則,正則的內容為a.*c,起始加號表示正正則

? ? * 反正則示例:-a.*c時一條反正則,正則的內容為a.*c,起始減號表示反正則

? ? * 如果一個規則的起始字符不為加號且不為減號,則該正則為正正則,正則的內容為自身

? ? * 例如a.*c是一條正正則,正則的內容為a.*c

? ? * @param rule 正則規則

? ? * @return 自身

? ? */

? ? public RegexRule addRule(String rule) {

? ? ? ? if (rule.length() == 0) {

? ? ? ? ? ? return this;

? ? ? ? }

? ? ? ? char pn = rule.charAt(0);

? ? ? ? String realrule = rule.substring(1);

? ? ? ? if (pn == '+') {

? ? ? ? ? ? addPositive(realrule);

? ? ? ? } else if (pn == '-') {

? ? ? ? ? ? addNegative(realrule);

? ? ? ? } else {

? ? ? ? ? ? addPositive(rule);

? ? ? ? }

? ? ? ? return this;

? ? }



? ? /**

? ? * 添加一個正正則規則

? ? * @param positiveregex

? ? * @return 自身

? ? */

? ? public RegexRule addPositive(String positiveregex) {

? ? ? ? positive.add(positiveregex);

? ? ? ? return this;

? ? }


? ? /**

? ? * 添加一個反正則規則

? ? * @param negativeregex

? ? * @return 自身

? ? */

? ? public RegexRule addNegative(String negativeregex) {

? ? ? ? negative.add(negativeregex);

? ? ? ? return this;

? ? }


? ? /**

? ? * 判斷輸入字符串是否符合正則規則

? ? * @param str 輸入的字符串

? ? * @return 輸入字符串是否符合正則規則

? ? */

? ? public boolean satisfy(String str) {

? ? ? ? int state = 0;

? ? ? ? for (String nregex : negative) {

? ? ? ? ? ? if (Pattern.matches(nregex, str)) {

? ? ? ? ? ? ? ? return false;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? int count = 0;

? ? ? ? for (String pregex : positive) {

? ? ? ? ? ? if (Pattern.matches(pregex, str)) {

? ? ? ? ? ? ? ? count++;

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? if (count == 0) {

? ? ? ? ? ? return false;

? ? ? ? } else {

? ? ? ? ? ? return true;

? ? ? ? }

? ? }

}

MyCrawler.java 爬取主類

package com.etoak.crawl.main;

import java.io.UnsupportedEncodingException;

import java.net.URLDecoder;

import java.net.URLEncoder;

import java.util.ArrayList;

import java.util.List;

import org.jsoup.select.Elements;

import com.alibaba.fastjson.JSON;

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;

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]);

? ? ? ? }

? ? }

? ? /**

? ? * 抓取過程

? ? *

? ? * @param seeds

? ? * @return

? ? */

? ? public void crawling(String[] seeds , String name) {

? ? ? ? //初始化 URL 隊列

? ? ? ? initCrawlerWithSeeds(seeds);

? ? ? ? //定義過濾器,提取以 http://www.baidu.com 開頭的鏈接

? ? ? ? LinkFilter filter = new LinkFilter() {

? ? ? ? ? ? public boolean accept(String url) {

? ? ? ? ? ? ? ? if (url.startsWith("https://www.jd.com"))

? ? ? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? ? ? else

? ? ? ? ? ? ? ? ? ? return false;

? ? ? ? ? ? }

? ? ? ? };

? ? ? ? //循環條件:待抓取的鏈接不空且抓取的網頁不多于 1000

? ? ? ? int m = 1;

? ? ? ? for (int i = 0; i < m; i++) {

? ? ? ? ? ? ? ? ? //先從待訪問的序列中取出第一個;

? ? ? ? ? ? ? ? ? String visitUrl = (String) Links.removeHeadOfUnVisitedUrlQueue();

? ? ? ? ? ? ? ? ? if (visitUrl == null){

? ? ? ? ? ? ? ? ? ? ? continue;

? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? //根據URL得到page;

? ? ? ? ? ? ? ? ? Page page = RequestAndResponseTool.sendRequstAndGetResponse(visitUrl);

? ? ? ? ? ? ? ? ? //對page進行處理: 訪問DOM的某個標簽

? ? ? ? ? ? ? ? ? System.out.println(page);

? ? ? ? ? ? ? ? ? Elements es = PageParserTool.select(page,"img[src]");

? ? ? ? ? ? ? ? ? if(!es.isEmpty()){

? ? ? ? ? ? ? ? ? ? ? System.out.println("下面將打印所有img[src]標簽: ");

? ? ? ? ? ? ? ? ? ? ? System.out.println(es);

? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? //得到超鏈接

? ? ? ? ? ? ? ? ? ArrayList<String>? links = PageParserTool.getAttrs(page,"img[src]","abs:src");

? ? ? ? ? ? ? ? ? m = links.size();

? ? ? ? ? ? ? ? ? try {

? ? ? FileTool.saveToLocal(page,URLDecoder.decode(name, "utf-8"));

? ? ? } catch (UnsupportedEncodingException e) {

? ? ? // TODO Auto-generated catch block

? ? ? e.printStackTrace();

? ? ? }

? ? ? ? ? ? ? ? ? if(links!=null&&links.size()>0){

? ? ? ? ? ? ? ? ? Links.addUnvisitedUrlQueue(links.get(3));

? ? ? ? ? ? ? ? ? System.out.println("新增爬取路徑: " + links);

? ? ? ? ? ? ? ? ? }

}


? ? }

? ? //main 方法入口

? ? public static void main(String[] args) {

? ? String as ="['帆布鞋']";

? ? List<Object> list =JSON.parseArray(as);

? ? /*JSONObject json = null;

json = RedisUtils.getObject("JDClassCid3");

if(json!=null){

list = (List<String>) json.get("list");

}else{

list = ShoppingGuideUtils.getClasss11();

Map<String, Object> map = new HashMap<String, Object>();

map.put("list", list);

RedisUtils.setObjectMap("JDClassCid3", map, RedisUtils.EXRP_DAY);

}*/

? ? System.out.println(list);

? ? if(list!=null&&list.size()>0){

? ? String name= "";

? ? for (int i = 0; i < list.size(); i++) {

? ? MyCrawler crawler = new MyCrawler();

? ? name = list.get(i).toString();

? ? try {

if(URLDecoder.decode(name, "utf-8").contains("二手")){//去除二手物品

continue;

}

} catch (UnsupportedEncodingException e2) {

// TODO Auto-generated catch block

e2.printStackTrace();

}

? ? try {

? ? name =URLEncoder.encode(name, "utf-8");

? ? } catch (UnsupportedEncodingException e1) {

? ? // TODO Auto-generated catch block

? ? e1.printStackTrace();

? ? }

? ? crawler.crawling(new String[]{"https://so.m.jd.com/ware/search.action?keyword="+name+"&searchFrom=category&sf=1&as=1"},name);

? ? try {

System.out.println("總計"+list.size()+"個===當前分類"+URLDecoder.decode(name, "utf-8")+"爬到"+i+"個");

} catch (UnsupportedEncodingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

? ? }



? ? /*MyCrawler crawler = new MyCrawler();

? ? String name= "ETC";

? ? try {

if(URLDecoder.decode(name, "utf-8").contains("二手")){

System.out.println("jies");

}

} catch (UnsupportedEncodingException e2) {

// TODO Auto-generated catch block

e2.printStackTrace();

}

try {

name =URLEncoder.encode(name, "utf-8");

} catch (UnsupportedEncodingException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

crawler.crawling(new String[]{"https://so.m.jd.com/ware/search.action?keyword="+name+"&searchFrom=category&sf=1&as=1"},name); */

}


}


我選的根url是京東是搜索接口,取出來合適的圖片,這里難點就在這,取出來html中的img集合,匹配度最高的,這得批跑抓取好幾次,還有比較有爭議的分類名稱,比如“蘋果”這種就得特殊處理


運行結果

文章主要參考:? 羅剛?老師的?書籍 << 自己動手寫網絡爬蟲>>?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380