


Comment utiliser le robot d'exploration Java pour explorer des images par lots
Crawling ideas
L'acquisition de ce genre d'image est en fait le téléchargement du fichier (HttpClient). Mais comme il ne s’agit pas seulement d’obtenir une image, il existe également un processus d’analyse de page (Jsoup).
Jsoup : Analysez la page html et obtenez le lien vers l'image.
HttpClient : Demandez le lien de l'image et enregistrez l'image localement.
Étapes spécifiques
Entrez d'abord dans l'analyse de la page d'accueil, il y a principalement les catégories suivantes (pas toutes les catégories ici, mais celles-ci suffisent, c'est juste pour apprendre C'est juste de la technologie. ), notre objectif est d'obtenir des photos dans chaque catégorie.
Analysons la structure du site Web. Je vais rester simple ici. L'image ci-dessous est la structure générale. Ici, une étiquette de classification est sélectionnée pour explication. Une page de balise de catégorie contient plusieurs pages de titre et chaque page de titre contient plusieurs pages d'images. (Correspondant à des dizaines d'images sur la page de titre)
Code spécifique
Importer un package jar dépendant du projet coordonnées Ou téléchargez directement le package jar correspondant et importez le projet.
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.3</version> </dependency>
Classe d'entité Classe d'images et d'outils HeaderUtil
Classe d'entité : Encapsulez les propriétés dans un objet, ce qui facilite son appel.
package com.picture; public class Picture { private String title; private String url; public Picture(String title, String url) { this.title = title; this.url = url; } public String getTitle() { return this.title; } public String getUrl() { return this.url; } }
Catégorie d'outils : UA en constante évolution (je ne sais pas si c'est utile, mais j'utilise ma propre IP, donc c'est probablement de peu d'utilité)
package com.picture; public class HeaderUtil { public static String[] headers = { "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)", "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11", "Opera/9.25 (Windows NT 5.1; U; en)", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", "Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12", "Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9", "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7", "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 " }; }
Télécharger la catégorie# 🎜🎜#
Le multi-threading est vraiment trop rapide De plus, je n'ai qu'une seule IP et il n'y a pas d'IP proxy disponible (je n'y connais pas grand chose). rapide.package com.picture; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Random; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import com.m3u8.HttpClientUtil; public class SinglePictureDownloader { private String referer; private CloseableHttpClient httpClient; private Picture picture; private String filePath; public SinglePictureDownloader(Picture picture, String referer, String filePath) { this.httpClient = HttpClientUtil.getHttpClient(); this.picture = picture; this.referer = referer; this.filePath = filePath; } public void download() { HttpGet get = new HttpGet(picture.getUrl()); Random rand = new Random(); //设置请求头 get.setHeader("User-Agent", HeaderUtil.headers[rand.nextInt(HeaderUtil.headers.length)]); get.setHeader("referer", referer); System.out.println(referer); HttpEntity entity = null; try (CloseableHttpResponse response = httpClient.execute(get)) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 200) { entity = response.getEntity(); if (entity != null) { File picFile = new File(filePath, picture.getTitle()); try (OutputStream out = new BufferedOutputStream(new FileOutputStream(picFile))) { entity.writeTo(out); System.out.println("下载完毕:" + picFile.getAbsolutePath()); } } } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { //关闭实体,关于 httpClient 的关闭资源,有点不太了解。 EntityUtils.consume(entity); } catch (IOException e) { e.printStackTrace(); } } } }
Il s'agit d'une classe d'outils permettant d'obtenir des connexions HttpClient afin d'éviter la consommation de performances liée à la création fréquente de connexions. (Mais comme j'utilise un seul thread pour explorer ici, ce n'est pas très utile. Je ne peux utiliser qu'une seule connexion HttpClient pour explorer. C'est parce que j'ai utilisé plusieurs threads pour explorer au début. , mais c'était banni après avoir obtenu quelques images, il a donc été remplacé par un robot d'exploration à thread unique, donc le pool de connexions a été laissé.)
package com.m3u8; import org.apache.http.client.config.RequestConfig; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; public class HttpClientUtil { private static final int TIME_OUT = 10 * 1000; private static PoolingHttpClientConnectionManager pcm; //HttpClient 连接池管理类 private static RequestConfig requestConfig; static { requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(TIME_OUT) .setConnectTimeout(TIME_OUT) .setSocketTimeout(TIME_OUT).build(); pcm = new PoolingHttpClientConnectionManager(); pcm.setMaxTotal(50); pcm.setDefaultMaxPerRoute(10); //这里可能用不到这个东西。 } public static CloseableHttpClient getHttpClient() { return HttpClients.custom() .setConnectionManager(pcm) .setDefaultRequestConfig(requestConfig) .build(); } }
package com.picture; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.select.Elements; import com.m3u8.HttpClientUtil; /** * 首先从顶部分类标题开始,依次爬取每一个标题(小分页),每一个标题(大分页。) * */ public class PictureSpider { private CloseableHttpClient httpClient; private String referer; private String rootPath; private String filePath; public PictureSpider() { httpClient = HttpClientUtil.getHttpClient(); } /** * 开始爬虫爬取! * * 从爬虫队列的第一条开始,依次爬取每一条url。 * * 分页爬取:爬10页 * 每个url属于一个分类,每个分类一个文件夹 * */ public void start(List<String> urlList) { urlList.stream().forEach(url->{ this.referer = url; String dirName = url.substring(22, url.length()-1); //根据标题名字去创建目录 //创建分类目录 File path = new File("D:/DragonFile/DBC/mzt/", dirName); //硬编码路径,需要用户自己指定一个 if (!path.exists()) { path.mkdir(); rootPath = path.toString(); } for (int i = 1; i <= 10; i++) { //分页获取图片数据,简单获取几页就行了 this.page(url + "page/"+ 1); } }); } /** * 标题分页获取链接 * */ public void page(String url) { System.out.println("url:" + url); String html = this.getHtml(url); //获取页面数据 Map<String, String> picMap = this.extractTitleUrl(html); //抽取图片的url if (picMap == null) { return ; } //获取标题对应的图片页面数据 this.getPictureHtml(picMap); } private String getHtml(String url) { String html = null; HttpGet get = new HttpGet(url); get.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36"); get.setHeader("referer", url); try (CloseableHttpResponse response = httpClient.execute(get)) { int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 200) { HttpEntity entity = response.getEntity(); if (entity != null) { html = EntityUtils.toString(entity, "UTf-8"); //关闭实体? } } else { System.out.println(statusCode); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return html; } private Map<String, String> extractTitleUrl(String html) { if (html == null) { return null; } Document doc = Jsoup.parse(html, "UTF-8"); Elements pictures = doc.select("ul#pins > li"); //不知为何,无法直接获取 a[0],我不太懂这方面的知识。 //那我就多处理一步,这里先放下。 Elements pictureA = pictures.stream() .map(pic->pic.getElementsByTag("a").first()) .collect(Collectors.toCollection(Elements::new)); return pictureA.stream().collect(Collectors.toMap( pic->pic.getElementsByTag("img").first().attr("alt"), pic->pic.attr("href"))); } /** * 进入每一个标题的链接,再次分页获取图片的链接 * */ private void getPictureHtml(Map<String, String> picMap) { //进入标题页,在标题页中再次分页下载。 picMap.forEach((title, url)->{ //分页下载一个系列的图片,每个系列一个文件夹。 File dir = new File(rootPath, title.trim()); if (!dir.exists()) { dir.mkdir(); filePath = dir.toString(); //这个 filePath 是每一个系列图片的文件夹 } for (int i = 1; i <= 60; i++) { String html = this.getHtml(url + "/" + i); if (html == null) { //每个系列的图片一般没有那么多, //如果返回的页面数据为 null,那就退出这个系列的下载。 return ; } Picture picture = this.extractPictureUrl(html); System.out.println("开始下载"); //多线程实在是太快了(快并不是好事,我改成单线程爬取吧) SinglePictureDownloader downloader = new SinglePictureDownloader(picture, referer, filePath); downloader.download(); try { Thread.sleep(1500); //不要爬的太快了,这里只是学习爬虫的知识。不要扰乱别人的正常服务。 System.out.println("爬取完一张图片,休息1.5秒。"); } catch (InterruptedException e) { e.printStackTrace(); } } }); } /** * 获取每一页图片的标题和链接 * */ private Picture extractPictureUrl(String html) { Document doc = Jsoup.parse(html, "UTF-8"); //获取标题作为文件名 String title = doc.getElementsByTag("h3") .first() .text(); //获取图片的链接(img 标签的 src 属性) String url = doc.getElementsByAttributeValue("class", "main-image") .first() .getElementsByTag("img") .attr("src"); //获取图片的文件扩展名 title = title + url.substring(url.lastIndexOf(".")); return new Picture(title, url); } }
BootStrap
Il y a une file d'attente d'exploration ici, mais je n'ai même pas fini d'explorer la première C'est parce que j'ai fait une erreur de calcul et compté deux ordres de grandeur de moins. Cependant, la fonctionnalité du programme est correcte.
package com.picture; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 爬虫启动类 * */ public class BootStrap { public static void main(String[] args) { //反爬措施:UA、refer 简单绕过就行了。 //refer https://www.mzitu.com //使用数组做一个爬虫队列 String[] urls = new String[] { "https://www.mzitu.com/xinggan/", "https://www.mzitu.com/zipai/" }; // 添加初始队列,启动爬虫 List<String> urlList = new ArrayList<>(Arrays.asList(urls)); PictureSpider spider = new PictureSpider(); spider.start(urlList); } }
Résultats d'exploration
Notes
Il y a une erreur de calcul ici, le code est le suivant :
for (int i = 1; i <= 10; i++) { //分页获取图片数据,简单获取几页就行了 this.page(url + "page/"+ 1); }
Ce programme est juste pour l'apprentissage. J'ai défini l'intervalle de téléchargement de chaque image à 1,5 seconde, et c'est un programme à thread unique, donc la vitesse semblera très lente. Mais cela n'a pas d'importance, tant que le programme fonctionne correctement, personne n'attendra vraiment que l'image soit téléchargée.
On estime que cela prend beaucoup de temps : 64800*1,5s = 97200s = 27h. Ceci n'est qu'une estimation approximative et ne prend pas en compte les autres temps d'exécution de. le programme, mais les autres heures peuvent être fondamentalement ignorées.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

Java est un langage de programmation populaire qui peut être appris aussi bien par les développeurs débutants que par les développeurs expérimentés. Ce didacticiel commence par les concepts de base et progresse vers des sujets avancés. Après avoir installé le kit de développement Java, vous pouvez vous entraîner à la programmation en créant un simple programme « Hello, World ! ». Une fois que vous avez compris le code, utilisez l'invite de commande pour compiler et exécuter le programme, et « Hello, World ! » s'affichera sur la console. L'apprentissage de Java commence votre parcours de programmation et, à mesure que votre maîtrise s'approfondit, vous pouvez créer des applications plus complexes.
