多线程实现百度图片爬虫

      由于百度图片采用异步加载的方式,因此不能通过静态标签<img src>匹配找到图片的url,可考虑通过向服务器发送ajax请求的方式下载图片。

      打开360浏览器或Chrom,按F12,切换到Network标签,然后将网页向下拉,观察发现地址栏的网址并没有发生变化,而图片在增加。


  可以发现在下拉过程中会不断出现avatarjson请求,点开请求头信息,分析两个请求URL

http://image.baidu.com/search/avatarjson?tn=resultjsonavatarnew&ie=utf-8&word=%E5%AE%8B%E4%BD%B3&cg=star&pn=90&rn=30&itg=0&z=0&fr=&width=&height=&lm=-1&ic=0&s=0&st=-1&gsm=5a

http://image.baidu.com/search/avatarjson?tn=resultjsonavatarnew&ie=utf-8&word=%E5%AE%8B%E4%BD%B3&cg=star&pn=120&rn=30&itg=0&z=0&fr=&width=&height=&lm=-1&ic=0&s=0&st=-1&gsm=78

变化的地方如下:

word:搜索关键字,要用URL Encode,即非字母字符被替换成%后加两位十六进制数;

pn:每次递增30,每次异步请求可加载30张图片;

gsm: pn的十六进制值;

因此每次请求我们只需改变pngsm的值即可,用page对请求页面计数,初次请求时page0,以后每次请求page1

 

将keyword进行URL Encode编码后,可以拼接出page次请求的URL

http://image.baidu.com/search/avatarjson?tn=resultjsonavatarnew&ie=utf-8&word="+keyword+"&cg=star&pn="+page*30+"&rn=30&itg=0&z=0&fr=&width=&height=&lm=-1&ic=0&s=0&st=-1&gsm="+Integer.toHexString(page*30)

请求返回JSON数据,点击preview标签,找到imgs


发现一张图片有4URLfromURL,middleURL,thumbURL,objURL,前三种有反爬措施,因此采用objURL.

 

因此得到图片爬取的流程: 

1)将搜索关键字keyword编码后得到请求地址;

2)得到该请求地址的JSON数据;

3)分析JSON数据匹配出objURL地址;

4)请求此地址下载图片。

 

多线程实现

  为了加快爬取的速度,采用多线程设计。  各个线程同时下载各自请求得到的图片,因此要确保每个线程每次请求时的page不同,因此为page操作要实现同步。

程序如下:

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;

/**
 * @author Administrator
 * 爬取百度图片,百度图片加载方式:异步加载,瀑布流式
 */
public class Crawer
{
	private static int page=-1;	
	private static final String ENCODE="UTF-8";//编码
	private static Lock lock=new ReentrantLock();
	/**
	 * 将中文转换成URL编码
	 * @param keyword	 
	 */
	public static String  encode(String keyword) throws UnsupportedEncodingException 
	{
		return new String(URLEncoder.encode(keyword,ENCODE).getBytes());
	}
	
	public static void main(String[] args) throws UnsupportedEncodingException 
	{
		String name="孙艺珍";
		String downloadPath="F:\\downloadPic\\"+name+"\\";
		String keyword=encode(name);
		for(int i=0;i<8;i++)
		{
			new Thread("Thread--"+i){
				public void run()
				{
					downloadPic(keyword,downloadPath);
				}
				
			}.start();
		}		
	}
	public static void downloadPic(String keyword,String downloadPath)
	{	 
		File path=new File(downloadPath);
		if(!path.exists())
			path.mkdirs();
		while(!Thread.interrupted())
		{
		   lock.lock();
		   try{
		       page++;
		   }finally{
			   lock.unlock();
		   }		   
		   String url="http://image.baidu.com/search/avatarjson?tn=resultjsonavatarnew&ie=utf-8&word="+keyword+"&cg=star&pn="+page*30+"&rn=30&itg=0&z=0&fr=&width=&height=&lm=-1&ic=0&s=0&st=-1&gsm="+Integer.toHexString(page*30);
		   String html=null;
		   try {
			html=getHtml(url);
			List<String> listUrl=getImgeUrl(html);
			download(listUrl,downloadPath);
		} catch (Exception e) {			
			e.printStackTrace();
		}	
	  }
	}
	/**
	 * 获取url页面的内容
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static String getHtml(String url) throws Exception
	{
		URL uri=new URL(url);
		StringBuffer sb=new StringBuffer();
		URLConnection connection=uri.openConnection();
		InputStream in=connection.getInputStream();
		byte[] buf=new byte[1024];	
		int length=0;
		while((length=in.read(buf,0,buf.length))>0)
			sb.append(new String(buf,ENCODE));
		in.close();		
		return sb.toString();	
	}
	/**
	 * 获取图片URL
	 * @param html
	 * @return 
	 */
	public static List<String> getImgeUrl(String html)
	{
		List<String> listUrl=new ArrayList<String>();
		String reg = "objURL\":\"http://.+?\\.jpg";
		Matcher matcher=Pattern.compile(reg).matcher(html);
		while(matcher.find())
			listUrl.add(matcher.group().substring(9));
		return listUrl;
	}
	public static void download(List<String> listUrl,String downloadPath)
	{		
		for(String  url:listUrl)
		{
			String imageName=url.substring(url.lastIndexOf("/")+1,url.length());
			try {
				URL uri=new URL(url);
				//URLConnection connection=uri.openConnection();
				//HttpURLConnection httpCon=(HttpURLConnection)connection;
				//InputStream in=httpCon.getInputStream();
				InputStream in=uri.openStream();				 
				String file=downloadPath+imageName;
				FileOutputStream fo=new FileOutputStream(new File(file));
				byte[] buf=new byte[1024];
				int length=0;
				while((length=in.read(buf,0,buf.length))!=-1)
					fo.write(buf, 0, length);
				System.out.println(Thread.currentThread().getName()+url+"下载完成!");
				in.close();
				fo.close();
			} catch (FileNotFoundException e1) {				
				System.out.println("无法下载图片!");
			} catch(IOException e2)	{
				System.out.println("发生IO异常!");
			}
		}
	}
}

运行效果:


 



  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值