爬虫思路
以酷安网用户粉丝较多的用户的个人中心为进口,获取该用户的全部粉丝的个人中心链接,用户头像链接和用户名,并分别放入队列。开启两个线程获取信息,一个线程获取队列中的用户的信息并放入队列,另一个线程负责从头像链接队列中取出链接并下载用户头像。
爬虫分析
用浏览器打开一个用户的粉丝列表(http://coolapk.com/u/[用户id]/contacts)
并查看源码
我们可以看到粉丝列表以HTML的ul标签显示,并且其id为dataList,ul标签中的各个li标签即为每一个用户的信息啦~再进一步分析,li标签中的img标签为用户头像。h4标签的内容即为用户名,h4标签中的a标签的href属性为用户的个人中心链接。
通过观察我们还知道:用户的粉丝列表链接=个人中心链接+ "/contacts"
这样我们就可以开始爬取头像了
用到的库
Jsoup:
作用:解析和操作HTML元素。下载地址:https://jsoup.org/download
HttpClient:
作用:下载图片。下载地址: http://hc.apache.org/downloads.cgi
代码
Main.java
package main; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; 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.impl.client.HttpClients; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; public class Main { //浏览器UA private static String UA="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"; //主机地址 private static final String HOST="http://coolapk.com"; //头像本地保存地址 private static final String SAVE_PAYH="D:/coolapk/"; //指示UserThread是否在运行 private static boolean isRun=false; //用户中心界面队列 private static MyQueue<String> userUrlQueue=new MyQueue<>(); //用户头像链接队列 private static MyQueue<String> userHeadUrlQueue=new MyQueue<>(); //用户名队列 private static MyQueue<String> userNameQueue=new MyQueue<>(); public static void main(String[] args) throws Exception { // TODO Auto-generated method stub userUrlQueue.put("http://coolapk.com/u/12202/contacts"); java.io.File f=new java.io.File(SAVE_PAYH); //如果文件夹不存在,则创建 if(!f.exists()) { f.mkdirs(); } start(); } /** * 开始 */ private static void start() { new UserThread().start(); new HeadThread().start(); } /** * 获取相关的链接 * @throws Exception */ private static void getUserUrl() throws Exception { String url=userUrlQueue.poll(); if(url!=null){ isRun=true; Connection connection=Jsoup.connect(url); connection.userAgent(UA); Document document=connection.get(); Element ulElement=document.getElementById("dataList"); org.jsoup.select.Elements liElements=ulElement.getElementsByTag("li"); if (liElements==null) { return; } for(Element li:liElements){ if(li==null) continue; //获取用户头像链接 String userHeadUrl=li.getElementsByTag("img").first().attr("src"); //获取一个用户的粉丝列表的url String userUrl=HOST+li.getElementsByTag("h4").first() .getElementsByTag("a").first() .attr("href")+"/contacts"; //获取一个用户的用户名 String userName=li.getElementsByTag("h4").first() .getElementsByTag("a").first().text(); //本地已保存就不再加入队列 if(!new File(SAVE_PAYH+userName+".jpg").exists()){ userUrlQueue.put(userUrl); userHeadUrlQueue.put(userHeadUrl); userNameQueue.put(userName); } } //队列空了,isRun=false isRun=false; } } /** * 获取图片并保存到本地 * @param imgUrl * @param localPath * @throws Exception */ private static void getImage(String imgUrl,String localPath) throws Exception { //System.out.println(imgUrl); CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpget= new HttpGet(imgUrl); CloseableHttpResponse resp=httpclient.execute(httpget); InputStream inputStream=resp.getEntity().getContent(); FileOutputStream fileOutputStream=new FileOutputStream(localPath); byte[] buf=new byte[1024]; int len=0; while ((len=inputStream.read(buf))!=-1) { fileOutputStream.write(buf, 0, len); fileOutputStream.flush(); } inputStream.close(); fileOutputStream.close(); } /** * 获取链接线程 * @author zyw * */ public static class UserThread extends Thread{ @Override public void run() { // TODO Auto-generated method stub //如果队列userUrlQueue不为空 while (!userUrlQueue.isEmpty()) { try { getUserUrl(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 获取头像线程 * @author zyw * */ public static class HeadThread extends Thread{ @Override public void run() { // TODO Auto-generated method stub //如果队列userHeadUrlQueue不为空,并且UserThread在工作 while (!userHeadUrlQueue.isEmpty()||isRun) { try { String imgUrl=userHeadUrlQueue.poll(); String userName=userNameQueue.poll(); getImage(imgUrl, SAVE_PAYH+userName+".jpg"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
MyQueue.java
package main; import java.util.LinkedList; import java.util.Queue; /** * 线程安全队列 * @author zyw * * @param <T> */ public class MyQueue<T> { private LinkedList<T> userUrlQueue=new LinkedList<T>(); private Object lock=new Object(); /** * 获取队列是否为空 * @return */ public boolean isEmpty() { return userUrlQueue.isEmpty(); } /** * 将一个元素插入队列尾 * @param t */ public void put(T t) { synchronized (lock) { userUrlQueue.addLast(t); } } /** * 队列头取出一个元素 * @return */ public T poll() { T t=null; synchronized (lock) { t=(T) userUrlQueue.removeFirst(); } return t; } }
效果图
时间: 2024-10-10 17:39:07