大数据互联网架构阶段 Java爬虫
2018-02-02 23:12
525 查看
Java爬虫
一 、 爬虫简介
http://www.lete.com , 乐贷网其实就是爬虫的简单应用 ,发送一个商品连接 , 获取商品信息目标
爬取京东所有商品的信息
封装在自己的Item实体类中
分析:
京东允许爬虫爬取数据么?
京东是允许爬虫的 , 没有反爬虫技术
爬虫产品:
httpClient :但是httpClient抓取的是整个页面 , 整夜字符串的处理、解析比较繁琐 , 数据的定位非常不准确 。
htmlUnit : 也获取整个页面 , 抓取页面也可以包含二次提交 , 数据定位也比较准确 , 但是爬取过程不稳定 , 在爬取过程中 需要断点续爬代码的编写 。
jsoup: 是一款比较稳定 , 定位准确 , 包含二次提交的java爬虫技术 。
python也可以做爬虫 , 使用beautifulSoup技术 ,底层原理与jsoup是一样的 。 只是语言不同。
jsoup
抓取整个页面抓取整个网站(以京东为列 , 抓取从首页能获取所有的连接地址)
抓取页面中某一个定位的数据
抓取二次提交ajax(如 : price)
抓取其他的jsonp数据 (如: 商品描述)
以上五种问题 , 如果都能解决 ,那么使用jsoup爬取任何网站都是可行的 。
案例
整个页面与httpclient无异
/** * 爬取网页 * @throws IOException * */ @Test public void testt_01() throws IOException { String url = "http://www.jd.com"; Connection connect = Jsoup.connect(url); Response execute = connect.execute(); System.out.println(execute.body()); }
整个网站
抓取绝大部分的连接地址
观察网站的连接大部分都是使用的a标签 , 连接在href中
使用jsoup定位a标签 , 获取所有a标签 , 然后获取href的值
/** * 爬取整个网站 * @throws IOException * */ @Test public void test_02() throws IOException { String url = "http://www.jd.com"; Document document = Jsoup.connect(url).get(); //寻找a标签 Elements elementsByTag = document.getElementsByTag("a"); for(Element element :elementsByTag) { String href = element.attr("href"); String val = element.val(); System.out.println("连接地址:"+href + "---"+val); } }
定位信息
/** * 爬取一个网页中的信息 * 定位具体标签中的数据 * @throws IOException * */ @Test public void test_03() throws IOException { String url= "http://item.jd.com/4329035.html"; //get请求 获取的是返回结构的document树 //excute获取的是返回的所有数据 Document doc = Jsoup.connect(url).get(); //选择器与jQ中的选择器使用一致 //为了 定位准确 , 使用父子选择器 , 确定唯一的定位 Element select = doc.select("ul li .p-img a").get(0); System.out.println(select.attr("href")); }
json二次提交获取信息
需要自己 寻找页面中发起 ajax的请求地址
/** * 抓取二次提交 * 商品价格是页面加载之后又通过ajax获取的 * @throws IOException * */ @Test public void test_04() throws IOException { String url = "http://p.3.cn/prices/mgets?skuIds=J_5089253"; Response response = Jsoup.connect(url).ignoreContentType(true).execute(); String json = response.body(); System.out.println(json); ObjectMapper mp = new ObjectMapper(); JsonNode jn = mp.readTree(json); //[{"op":"8388.00","m":"9999.00","id":"J_5089253","p":"8388.00"}] //直接获取到的是数组 ,需要获取到第一个元素 String price = jn.get(0).get("p").asText(); System.out.println(price); }
jsonp数据
/** * 获取jsonp请求数据 * @throws IOException * */ @Test public void test_05() throws IOException { String url = "http://d.3.cn/desc/4329035"; String jsonDesc = Jsoup.connect(url).ignoreContentType(true).execute().body(); System.out.println(jsonDesc); String data = jsonDesc.substring(jsonDesc.indexOf("(")+1, jsonDesc.lastIndexOf(")")); System.out.println(data); ObjectMapper mp = new ObjectMapper(); JsonNode jn = mp.readTree(data); String desc = jn.get("date").asText(); System.out.println(desc); }
爬取京东商品信息
/** * 爬取京东商品的所有商品信息 * @author outman * 2018 - 1 - 31 - 17:48 * 步骤: * 1. 先获取所有的商品三级分类链接 * 2. 访问商品分类链接后获取一个分类下所有商品的链接(可能存在分页的情况) * 3. 访问商品链接后获取商品信息 * * 过程中要十分注意异常的处理 * 在爬取过程中一旦出现异常 , 后续的过程也将受到影响 , 导致整个数据错乱 * */ public class JDCrawler { private static SqlSession session ; static { //获取一个数据流 InputStream in; try { in = Resources.getResourceAsStream("mybatis-config.xml"); //创建一个工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); //创建一个会话 session = factory.openSession(true);//true表示自动提交 , 默认为false , 需要手动提交 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 入口函数 * @throws Exception * */ public static void main (String[] args) throws Exception { //测试 //http://www.jd.com/allSort.aspx 商品 分类页面 // getItemCatUrls("http://www.jd.com/allSort.aspx"); //list.jd.com/list.html?cat=12379,13302,13313 某一分类下的商品展示页面 // getItemsPageUrls("http://list.jd.com/list.html?cat=12379,13302,13313"); //http://list.jd.com/list.html?cat=12379,13302,13313&page=2 商品展示页面 // getItemUrls("http://list.jd.com/list.html?cat=12379,13302,13313&page=2"); //item.jd.com/12017077901.html 商品信息页面 // getItem("http://item.jd.com/12017077901.html"); // 12017077901某一个商品的ID // getPrice(new Long("12017077901")); //完整测试 List<String> itemCatUrls = getItemCatUrls("http://www.jd.com/allSort.aspx"); for(String itemCaturl :itemCatUrls) { System.out.println("商品分类链接:"+itemCaturl); List<String> itemsPageUrls = getItemsPageUrls(itemCaturl); for(String itemsPageUrl : itemsPageUrls) { System.out.println("商品展示页面链接:"+itemsPageUrl); List<String> itemUrls = getItemUrls(itemsPageUrl); for(String itemUrl : itemUrls) { System.out.println("商品链接:"+itemUrls); Item item = getItem(itemUrl); saveItem(item); System.out.println(item); } } } } /** * 获取京东商品的所有分类链接 * @throws Exception * */ public static List<String> getItemCatUrls(String url) throws Exception{ //记录数据数量 Integer hrefPreNum = 0 ; List<String> itemCatUrls = new ArrayList<String>(); //这里选择抛出异常 , 这里如果抛出异常 , 说明url有问题 , 或者网络有问题 , 后续的操作没有任何意义 Document doc = Jsoup 4000 .connect(url).get(); Elements eles = doc.select("dl dd a"); for(Element ele : eles) { String href = ele.attr("href"); hrefPreNum += 1; if(href.startsWith("//list.jd.com/")) { itemCatUrls.add("http:"+href); // System.out.println(href); } } System.out.println("获取到的总三级分类链接量:"+hrefPreNum); System.out.println("数据清洗后的数量:"+itemCatUrls.size()); return itemCatUrls; } /** * 获取三级分类下所有商品页面的链接 * 商品展示可能存在分页的情况 * 所以在获取所有的商品链接之前需要先获取 所有的商品分类页 * */ public static List<String> getItemsPageUrls(String url){ List<String> itemsPages = new ArrayList<String>(); //从商品展示页面获取分页信息 String num; try {//抛出异常 , 如果 出现异常则继续执行 , 丢失一点信息是正常的 num = Jsoup.connect(url).get().select("#J_topPage span i").get(0).text(); Long numL = new Long(num); for(int i = 1 ; i<=numL ; i++) { String pageUrl = url+"&page="+i; // System.out.println(pageUrl); itemsPages.add(pageUrl); } } catch (Exception e) { e.printStackTrace(); } return itemsPages; } /** * 获取每个商品分类页面的商品链接 * */ public static List<String> getItemUrls(String url){ List<String> itemUrls = new ArrayList<String>(); try { Elements eles = Jsoup.connect(url).get().select(" li div .p-img a"); for(Element ele : eles) { String itemUrl = ele.attr("href"); itemUrls.add("http:"+itemUrl); } } catch (Exception e) { System.out.println("获取商品展示页面的商品链接出错:"+url); } return itemUrls; } /** * 访问商品链接 , 获取商品数据 * */ public static Item getItem (String url) { Item item = new Item(); Long id = null; try { Document doc = Jsoup.connect(url).get(); //获取id //item.jd.com/12016709876.html id = new Long(url.substring(url.lastIndexOf("/")+1, url.indexOf(".html"))); //获取title String title = doc.select("#name h1").get(0).text(); //获取卖点 获取到的 值为"" 说明页面时是通过ajax方式请求 需要json格式的数据 // String sellPoint = doc.select("#p-ad").get(0).text(); String sellPoint = getSellPoint(id); //获取价格 价格是通过ajax二次请求的 // Long price = new Long(doc.select(".dd .p-price .price").get(0).text()); Long price = getPrice(id); //获取图片 // String img = doc.select("#spec-n1 img").attr("src"); String img = getImg(url); // System.out.println(img); //获取商品详情 // String desc = doc.select("J-detail-content").get(0).text(); String desc = getDesc(id); //封装属性 item.setId(id); item.setTitle(title); item.setSellPoint(sellPoint); item.setPrice(price); item.setImg(img); item.setDesc(desc); System.out.println(item); } catch (Exception e) { // TODO Auto-generated catch block System.out.println("获取商品信息失败"); } return item; } /** * 爬取卖点 * 由于商品价格是页面加载完成之后 , 有通过ajax获取的 , 所以单独爬取json格式的数据 * 通过页面分析 得到卖点的url * http://ad.3.cn/ads/mgets?skuids=AD_ +12017077901 * */ public static String getSellPoint(Long id) { String sellPoint = null; try { Response resp = Jsoup.connect("http://ad.3.cn/ads/mgets?skuids=AD_"+id).ignoreContentType(true).execute(); ObjectMapper mapper = new ObjectMapper(); sellPoint = mapper.readTree(resp.body()).get(0).get("ad").asText(); } catch (Exception e) { // TODO Auto-generated catch block System.out.println("获取卖点失败"); } return sellPoint; } /** * 爬取商品价格 * 由于商品价格是页面加载完成之后 , 有通过ajax获取的 , 所以单独爬取 * 通过页面分析 得到商品价格的链接 //p.3.cn/prices/get?skuid=id * */ public static Long getPrice(Long id) { Long price = null; try { Response resp = Jsoup.connect("http://p.3.cn/prices/get?skuid="+id).ignoreContentType(true).execute(); ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(resp.body()).get(0); price = jsonNode.get("m").asLong(); // System.out.println(price); } catch (Exception e) { System.out.println("获取价格失败"); } return price; } /** * 获取商品图片 * 通过分析页面 , 得到图片的请求地址 * */ public static String getImg(String url) { String img = ""; Document doc; try { doc = Jsoup.connect(url).get(); //获取页面大图的地址 String bigsrc = doc.select("#spec-n1 img").attr("src"); // System.out.println("大图地址:"+bigsrc); //获取小图地址 Elements smallsrcs = doc.select("#spec-list div ul li img"); for(Element ele : smallsrcs) { String src = ele.attr("src"); // System.out.println("小图地址:"+src); //将小图地址替换成大图 String newSrc = src.replace("n5", "n1"); img+=newSrc+";"; // System.out.println(newSrc); } } catch (Exception e) { // TODO Auto-generated catch block System.out.println("获取图片失败"); } img = img.substring(0 , img.length()-1); return img; } /** * 爬取商品详情 * 商品详情是页面加载完成之后 , 通过jsonp获取的 , 需要单独获取 * http://dx.3.cn/desc/10316672107 * */ public static String getDesc(Long id) { String desc = null; try { Response resp = Jsoup.connect("http://dx.3.cn/desc/"+id).ignoreContentType(true).execute(); ObjectMapper mapper = new ObjectMapper(); String body = resp.body(); body = body.substring(body.indexOf("(")+1, body.lastIndexOf(")")); desc = mapper.readTree(body).get("content").asText(); } catch (Exception e) { // TODO Auto-generated catch block System.out.println("获取不到"+id+"的商品描述"); } return desc; } /** * 数据入库 * */ public static void saveItem(Item item) { session.insert("ItemMapper.saveItem" , item); } }
爬虫的注意事项
网络不稳定 , 最好使用完整的严谨 的逻辑(断点续爬)爬虫代码量不大(逻辑种类不多) , 最重要 的是页面结构的分析
网站改版导致爬虫的代码更新 。
反爬虫技术
频繁修改样式关键字(最简单的反爬虫机制)
nginx就可以反爬虫 (使用nginx黑名单)
jsoup的连接 请求头和浏览器请求头不一样
jsoup可以用代码模拟请求头—伪装请求头 参考: http://jilongliang.iteye.com/blog/2048459
查看访问频率 , 如果频率过高 , 则封ip一段时间
问题
数据是会每天更新或添加的 ,怎样在原有的基础上爬取最新的数据相关文章推荐
- 大数据互联网架构阶段 Spring框架导致的406错误
- 架构师之路 Java hadoop 互联网架构 大数据 分布式 高并发 中间件
- 大数据 互联网架构阶段 Redis(三)redis集群
- 大数据互联网架构阶段 Linux下安装mysql启动的常见问题
- 大数据 互联网架构阶段 电商项目简介
- 大数据 互联网架构阶段 Nginx的使用
- 涵盖从java入门到深入架构,Linux、云计算、分布式、大数据Hadoop、ios、Android、互联网技术应有尽有
- 大数据 互联网架构阶段 Redis
- 大数据互联网架构阶段 全文检索技术
- 大数据互联网架构阶段 前台系统架构 跨域请求
- Java实现爬虫给App提供数据(Jsoup 网络爬虫)
- iOS—网络实用技术OC篇&网络爬虫-使用java语言抓取网络数据
- 大数据课程体系-学习笔记-第一阶段-Java IDE
- Atitit. 数据约束 校验 原理理论与 架构设计 理念模式java php c#.net js javascript mysql oracle
- 大数据课程体系-学习笔记-第一阶段-Java Thread
- 大数据课程体系-学习笔记-第一阶段-Java Reflect
- java 爬虫实现爬豆瓣电影数据并存入mysql数据库
- 关于java开发、网络爬虫、自然语言处理、数据挖掘简介与关系小结
- 我的架构演化笔记 12:Nutch1.7 构建互联网爬虫
- 数据分析之分布式爬虫---分布式爬虫架构