多线程实现百度图片爬虫
由于百度图片采用异步加载的方式,因此不能通过静态标签<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
变化的地方如下:
word:搜索关键字,要用URL Encode,即非字母字符被替换成%后加两位十六进制数;
pn:每次递增30,每次异步请求可加载30张图片;
gsm: pn的十六进制值;
因此每次请求我们只需改变pn及gsm的值即可,用page对请求页面计数,初次请求时page为0,以后每次请求page加1。
将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
发现一张图片有4种URL:fromURL,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异常!");
- }
- }
- }
- }
运行效果:
来源:http://blog.csdn.net/gds2014/article/details/51851695