定向爬虫:动态加载网页的爬取
2016-01-26 20:06
106 查看
×× 前几天看了一下豆瓣电影的内容,想从豆瓣电影的分类排行榜 · · · · · 中爬取多一点的电影信息。点击一个类型进去之后发现它里面的电影信息时需要你不断往下拉动滚动条之后才会动态地加载更多的电影信息并显示出来。
观察了一下发现了它采用的是AJAX异步请求(通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新).这样就导致了查看到源代码内容(因为它是静态的)与网页内容不同。
F12之后发现了可疑的js文件,如下:
![](https://img-blog.csdn.net/20160126192046443)
通过浏览器打开这个js文件发现它的里面就是从服务器端返回的电影信息的一个json对象数组。这个js文件的url是这样的:
https://movie.douban.com/j/chart/top_list?type=24&interval_id=100%3A90&action=&start=20&limit=20
每个这样的url除了start和limit后面的数字不一致之外其他的都相同,那么这两个数据表示的是什么呢???我想答案应该是从第20个电影信息开始往后读取20个电影的信息!
那么问题来了?!
那么这个url怎么获取呢???
1> 知道了这个url我们就不需要从网页源代码中去寻找电影的信息,每个类型的电影下面构造这样的url直接connect接收返回的json数据,分析json数据然后从json对象数组中提取电影信息。
2>每个类型下面的电影总数怎么知道?知道了这种类型有多少个电影之后直接将start=0&limit=电影总数,就可以一次返回所有的电影信息的json数据。
3> 通过观察发现了一个这样的js文件:
![](https://img-blog.csdn.net/20160126195922182)
点击这个count的url之后发现这个里面就是每个类型的电影总数,
![](https://img-blog.csdn.net/20160126200039113)
这里面的total就是电影总数。
4> 这样我们就可以开始敲代码了。
!首先进入到有各种类型的页面(也就是这样的)
![](https://img-blog.csdn.net/20160126200406627)
这样就可以运行了
观察了一下发现了它采用的是AJAX异步请求(通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新).这样就导致了查看到源代码内容(因为它是静态的)与网页内容不同。
F12之后发现了可疑的js文件,如下:
通过浏览器打开这个js文件发现它的里面就是从服务器端返回的电影信息的一个json对象数组。这个js文件的url是这样的:
https://movie.douban.com/j/chart/top_list?type=24&interval_id=100%3A90&action=&start=20&limit=20
每个这样的url除了start和limit后面的数字不一致之外其他的都相同,那么这两个数据表示的是什么呢???我想答案应该是从第20个电影信息开始往后读取20个电影的信息!
那么问题来了?!
那么这个url怎么获取呢???
1> 知道了这个url我们就不需要从网页源代码中去寻找电影的信息,每个类型的电影下面构造这样的url直接connect接收返回的json数据,分析json数据然后从json对象数组中提取电影信息。
2>每个类型下面的电影总数怎么知道?知道了这种类型有多少个电影之后直接将start=0&limit=电影总数,就可以一次返回所有的电影信息的json数据。
3> 通过观察发现了一个这样的js文件:
点击这个count的url之后发现这个里面就是每个类型的电影总数,
这里面的total就是电影总数。
4> 这样我们就可以开始敲代码了。
!首先进入到有各种类型的页面(也就是这样的)
public class Test { private static HashMap<String,String> urlandnames = new HashMap<String, String>(); public static void main(String[] args) { String url = "http://movie.douban.com/chart"; GetMoviesName getMoviesName = new GetMoviesName(url); try { urlandnames = getMoviesName.getAllKinds(); } catch (IOException e) { e.printStackTrace(); } Iterator it = urlandnames.keySet().iterator(); //使用iterator遍历hashmap while (it.hasNext()){ RunnableOfMoviename runnable = new RunnableOfMoviename((String) it.next()); //它的返回值是object类型 Thread thread = new Thread(runnable); thread.start(); //创建多个线程并启动 } } }
public class GetMoviesName { private String html; private String url; private String kindofurl; HashMap<String, String> hrefandname = new HashMap<String, String>(); //保存电影分类的url和类型 public GetMoviesName(String url) { this.url = url; } public HashMap<String, String> getAllKinds() throws IOException { Document kinds = Jsoup.connect(url).timeout(10000).get(); Element element = kinds.getElementById("content"); Elements elements = element.getElementsByClass("types"); for (Element t:elements){ Elements elem = t.getElementsByTag("a"); for (Element a:elem){ //构造每种类型电影的链接 String kindurl = "http://movie.douban.com"+a.attr("href"); hrefandname.put(kindurl,t.text()); } } return hrefandname; } }
public class RunnableOfMoviename implements Runnable { private String url = null; //每创建一个线程就获取一种类型里面的所有电影名 private String nameurl = null; public RunnableOfMoviename(String url) { this.url = url; } public void run() { String[] tempurl = url.split("&"); //获取到每个电影类型的js文件的url,得到该类型的电影个数 String s1 = "http://movie.douban.com/j/chart/top_list_count?"; String finalurl = s1+tempurl[1]+"&"+tempurl[2]; String document = null; try { document = Jsoup.connect(finalurl).timeout(10000).ignoreContentType(true).execute().body(); } catch (IOException e) { e.printStackTrace(); } JsonParser parser = new JsonParser(); //json解析器 JsonObject jsonObject = (JsonObject)parser.parse(document); //获取json对象 int movienum = jsonObject.get("total").getAsInt(); nameurl = "http://movie.douban.com/j/chart/top_list?"+tempurl[1]+"&"+tempurl[2]+"&action=&start=0&limit="+movienum; String doc = null; try { doc = Jsoup.connect(nameurl).timeout(10000).ignoreContentType(true).execute().body(); } catch (IOException e) { e.printStackTrace(); } //将json的一个对象数组解析成JsonElement对象 JsonElement element = null; try { element = parser.parse(doc); //通过JsonParser对象可以把json格式的字符串解析成一个JsonElement对象 }catch (NullPointerException e){ e.printStackTrace(); } JsonArray jsonArray = null; if (element.isJsonArray()){ //JsonElement对象如果是一个数组的话转化成jsonArray jsonArray = element.getAsJsonArray(); } Iterator it = jsonArray.iterator(); //遍历json的对象数组,将每一个对象里的title输出 while(it.hasNext()){ JsonObject e = (JsonObject)it.next(); Movies movie = new Movies(); String doubletitle = e.get("title").getAsString(); String name = doubletitle.split("\"")[0]; //字符串分割 double score = e.get("score").getAsDouble(); String release_date = e.get("release_date").getAsString(); JsonArray Elements = e.get("types").getAsJsonArray(); ArrayList<String> array = new ArrayList<String>(); for (Object o:Elements){ array.add(o.toString().split("\"")[1]); } movie.setName(name); movie.setTypes(array.toString()); movie.setRelease_date(release_date); movie.setScore(score); } } }
这样就可以运行了
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- Scrapy的架构介绍
- 爬虫笔记
- 如何优雅地使用c语言编写爬虫
- PHP实现简单爬虫的方法
- NodeJS制作爬虫全过程(续)
- PHP爬虫之百万级别知乎用户数据爬取与分析
- 一个PHP实现的轻量级简单爬虫
- nodejs爬虫抓取数据乱码问题总结
- 基于Node.js的强大爬虫 能直接发布抓取的文章哦
- nodejs爬虫抓取数据之编码问题
- python实现爬虫统计学校BBS男女比例(一)
- python实现爬虫统计学校BBS男女比例之数据处理(三)
- JAVA使用爬虫抓取网站网页内容的方法
- 零基础写Java知乎爬虫之抓取知乎答案
- 零基础写Java知乎爬虫之先拿百度首页练练手
- Java实现爬虫给App提供数据(Jsoup 网络爬虫)
- 基于Java HttpClient和Htmlparser实现网络爬虫代码
- 零基础写Java知乎爬虫之获取知乎编辑推荐内容
- python实现爬虫统计学校BBS男女比例之多线程爬虫(二)