Java网络爬虫——jsoup快速上手,爬取京东数据。同时解决‘京东安全’防爬问题

文章目录
  • * 介绍
    
    • maven坐标
    • jsoup使用
    •   * 1.解析url,获取前端代码
      
      • 2.解决京东安全界面跳转
      • 3.获取每一组的数据
      • 4.获取商品数据的具体信息
      • 4.最终代码
    • 补充一:获取p-price出现空指针异常

介绍

网络爬虫,就是在浏览器上,代替人类爬取数据
,Java网络爬虫就是通过Java编写爬虫代码,代替人类从网络上爬取信息数据。程序员通过设定既定的规则,让程序代替我们从网络上获取海量我们需要的数据,比如图片,企业信息等。爬虫的关键是对于网页信息的解析。

什么是jsoup:

jsoup 是一个用于处理现实世界HTML的Java库。它提供了一个非常方便的API,用于获取URL以及提取和操作数据,使用最好的HTML5
DOM方法和CSS选择器

maven坐标

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.11.3</version>
</dependency>

jsoup使用

  • 连接url,爬取网页代码(html代码)
  • 解析网页代码,获取需要部分的数据

我们以解析京东网页,红框数据为例

在这里插入图片描述

1.解析url,获取前端代码
package com.xhf;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.io.IOException;
import java.net.URL;

public class JsoupTest {
    static String url = "https://search.jd.com/Search?keyword=%E9%A4%90%E5%B7%BE%E7%BA%B8";

    public static void main(String[] args) throws IOException {
        // 解析网页, document就代表网页界面
        Document document = Jsoup.parse(new URL(url), 5000);
        // 打印获取前端代码
        System.out.println(document);
    }
}
2.解决京东安全界面跳转

直接通过url访问,经常遇到弹出京东安全的界面

<!doctype html>
<html lang="en"> 
<head> 
<meta charset="utf-8"> 
<meta http-equiv="X-UA-Compatible" content="IE=edge"> 
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,maximum-scale=1.0,viewport-fit=cover"> 
<title>京东安全</title> 
<link href="https://cfe.m.jd.com/privatedomain/risk_handler/03101900/css/app.6f723501.css" rel="preload" as="style">
<link href="https://cfe.m.jd.com/privatedomain/risk_handler/03101900/js/app.js" rel="preload" as="script">
<link href="https://cfe.m.jd.com/privatedomain/risk_handler/03101900/js/chunk-vendors.js" rel="preload" as="script">
<link href="https://cfe.m.jd.com/privatedomain/risk_handler/03101900/css/app.6f723501.css" rel="stylesheet">
</head> 
<body> <!-- 不要删除这个div, class请勿修改--> 
<div class="ipaas-floor-app"></div> 
<script type="text/javascript" src="https://cfe.m.jd.com/privatedomain/risk_handler/03101900/js/chunk-vendors.js"></script>
<script type="text/javascript" src="https://cfe.m.jd.com/privatedomain/risk_handler/03101900/js/app.js"></script>                             
</body>
</html>

这算是对于爬取数据的一种反制措施。直接通过url请求,服务器会认为客户端没有登录,因此会跳出京东安全的登陆界面,让他们登录
。以前可以通过添加header解决,现在得添加cookie了。获取cookie的方式如下

在这里插入图片描述
在这里插入图片描述

  1. 空白处右击鼠标
  2. 选择检查
  3. 右边栏中选择网络。如果没有,点击加号(更多工具),选择网络
  4. 找到Search大头的请求,如果没有,刷新重发请求
  5. 选中请求,查看标头
  6. 选择cookies,找到以thor为key的cookie

以下,就是修正后的代码

package com.xhf;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class JsoupTest {
    static String url = "https://search.jd.com/Search?keyword=%E9%A4%90%E5%B7%BE%E7%BA%B8";
    
    public static void main(String[] args) throws IOException {
        // 设置cookie
        Map<String, String> cookies = new HashMap<String, String>();
        cookies.put("thor", "03F9B0325C5DCD2FCCDB435C227FD474D0B53C9143EB5DDA60599BDB9AE7A415B7CFEB4418F01DDEB8B8B9DD502D366A4E0BA2D84A0FE6CB6658061484CA95D230C7B76A36E31F4B329D2EFAC7DCD1E526F3C416CC50617276FED57FAF618892895784CB6446F6B8468A807290C12C3BA1C99DD0C0939C48C4E69681CA900EA9");
        // 解析网页, document就代表网页界面
        Document document = Jsoup.connect(url).cookies(cookies).get();
        System.out.println(document);
    }
}
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<meta http-equiv="Cache-Control" content="max-age=300">
<link rel="dns-prefetch" href="//search.jd.com">
<link rel="dns-prefetch" href="//item.jd.com">
<link rel="dns-prefetch" href="//list.jd.com">
<link rel="dns-prefetch" href="//p.3.cn">
<link rel="dns-prefetch" href="//misc.360buyimg.com">
<link rel="dns-prefetch" href="//nfa.jd.com">
<link rel="dns-prefetch" href="//d.jd.com">
<link rel="dns-prefetch" href="//img12.360buyimg.com">
<link rel="dns-prefetch" href="//img13.360buyimg.com">
<link rel="dns-prefetch" href="//static.360buyimg.com">
<link rel="dns-prefetch" href="//csc.jd.com">
<link rel="dns-prefetch" href="//mercury.jd.com">
<link rel="dns-prefetch" href="//x.jd.com">
<link rel="dns-prefetch" href="//wl.jd.com">
<title>餐巾纸 - 商品搜索 - 京东</title>
<meta name="Keywords" content="餐巾纸,京东餐巾纸">
<meta name="description"

content=“在京东找到了餐巾纸305051件餐巾纸的类似商品,其中包含了餐巾纸价格、餐巾纸评论、餐巾纸导购、餐巾纸图片等相关信息”>

jsoup中的document可以当作js中的document使用,解析网站内容就是在js中操作document,获取信息

3.获取每一组的数据

在这里插入图片描述

我们发现,所有的商品数据都是通过ul标签进行渲染

在这里插入图片描述

每单个数据,则是用li标签渲染

所以,如果我们要获取每个商品数据,我们可以先通过class,获取ul元素 ,然后选择出ul元素内包含的所有li元素

        // 通过class获取ul标签
        Elements ul = document.getElementsByClass("gl-warp clearfix");
        // 获取ul标签下的所有li标签
        Elements liList = ul.select("li");
        for (Element element : liList) {
            System.out.println("------------------");
            System.out.println(element);
            System.out.println();
        }
------------------
<li data-sku="1297484" data-spu="1297484" ware-type="10" bybt="0"

class=“gl-item”>

------------------
<li data-sku="3092062" data-spu="3092062" ware-type="10" bybt="0"

class=“gl-item”>


…其余数据不做展示

4.获取商品数据的具体信息

通过遍历上述代码中出现的liList,可以获取到每一个li元素。每个元素都代表了商品的一组信息。具体如下所示。

在这里插入图片描述

如果我们要获取更为具体的信息,比如价格,图片,介绍等信息。我们就需要对li标签所封装的对象进行数据的截取。

在这里插入图片描述

我们可以用getElementsByTag("img")来获取带有img标签的对象,然后获取其data-lazy-img属性的数据

String pict = element.getElementsByTag("img").first().attr("data-lazy-img");
  • 价格在这里插入图片描述

我们可以通过getElementsByClass("p-price")的方式获取对象,然后获取其中内容

    String price = element.getElementsByClass("p-price").first().text();
  • shop名称,类似价格获取方式
4.最终代码
package com.xhf;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * 解析京东界面, 爬取商品数据
 */
public class JsoupTest {
    static String url = "https://search.jd.com/Search?keyword=%E9%A4%90%E5%B7%BE%E7%BA%B8";

    public static void main(String[] args) throws IOException {
        // 设置cookie
        Map<String, String> cookies = new HashMap<String, String>();
        cookies.put("thor", "03F9B0325C5DCD2FCCDB435C227FD474D0B53C9143EB5DDA60599BDB9AE7A415B7CFEB4418F01DDEB8B8B9DD502D366A4E0BA2D84A0FE6CB6658061484CA95D230C7B76A36E31F4B329D2EFAC7DCD1E526F3C416CC50617276FED57FAF618892895784CB6446F6B8468A807290C12C3BA1C99DD0C0939C48C4E69681CA900EA9");
        // 解析网页, document就代表网页界面
        Document document = Jsoup.connect(url).cookies(cookies).get();

        // 通过class获取ul标签
        Elements ul = document.getElementsByClass("gl-warp clearfix");
        // 获取ul标签下的所有li标签
        Elements liList = ul.select("li");
        for (Element element : liList) {
            System.out.println("------------------");
            String pict = element.getElementsByTag("img").first().attr("data-lazy-img");
            String price = element.getElementsByClass("p-price").first().text();
            String shopName = element.getElementsByClass("p-shop").first().text();
            System.out.println(pict);
            System.out.println(price);
            System.out.println(shopName);
        }
    }
}

补充一:获取p-price出现空指针异常

有不少观众在爬取网页代码时,在获取p-price属性时出现了空指针问题(如下图所示),作为文章的补充内容,统一回复一下

![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/358016ab33244ae297c444c1a7385b16.png)

对于某些京东页面 (有些界面存在这样的情况,有的没有),每个商品元素可能存在多份图片
。一种是详细图、另一种是缩略图。在前端代码中,详细图是被外层li标签 包裹,外层li标签含有p-price属性
;而缩略图被内层li标签 包裹,内层li标签不含有p-price属性 。当在进行爬虫时,爬取到内层li标签时,因为没有p-
price属性,因此返回null值。调用空对象的方法,自然抛出空指针异常问题。

这么说有些抽象,我们上图解释

![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/48988f374f424f7eaac5fd9552afecc4.png)
如上图所示,外层li标签包裹整个商品数据,同时包含了图片、价格等信息

![在这里插入图片描述](https://img-
blog.csdnimg.cn/direct/7b90829d90c04a808a4e16317c31db6a.png)
而这幅图就是内层li标签所包裹的对象——缩略图信息。因为缩略图不含有价格信息,因此代码获取不到对应信息。

针对上述分析,我们可以在获取li标签时进行内外层次的区分。过滤掉内层li标签 ,我们不需要缩略图的信息。

仔细观察,我们发现内外li标签存在以下区别

  • 外层li标签,class = "gl-item"
  • 内层li标签,class = "ps-item"

因此在遍历li时,可以根据class进行筛选,具体代码如下

// 过滤内层标签
if ("ps-item".equals(element.attr("class"))) {
    continue;
}

通过.attr("class")获取标签的class属性,如果class为ps-item,则当前标签为内层标签,过滤

完整代码

public class JsoupTest {
    static String url = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&wq=%E6%89%8B%E6%9C%BA&pvid=8858151673f941e9b1a4d2c7214b2b52&czLogin=1";

    public static void main(String[] args) throws IOException {
        // 设置cookie
        Map<String, String> cookies = new HashMap<String, String>();
        cookies.put("thor", "51664BB815480B40C9BC99D1E3E76D810043E59D85A51BA3D7CF12A986735FD21314241E8DACE095E51DC048D68501E00F568A0A6387017449D23996F3FF832BF501CCCD7E17747CBBD81D86B59C2DAD1E8ADD845F3D78D34F3F7C98B077CC6122B5EA67CB52C5E3E2297F0C00C70F048384E7C719D954A3C3B925E7B7DEBAD77964C1AD145AAAA2A0797B928B4ABC3EEA676CD673C2283BFD0CEC7738C0156C");
        // 解析网页, document就代表网页界面
        Document document = Jsoup.connect(url).cookies(cookies).get();

        // 通过class获取ul标签
        Elements ul = document.getElementsByClass("gl-warp clearfix");
        // 获取ul标签下的所有li标签
        Elements liList = ul.select("li");
        for (Element element : liList) {
            System.out.println("------------------");
            // 过滤内层标签
            if ("ps-item".equals(element.attr("class"))) {
                continue;
            }
            String pict = element.getElementsByTag("img").first().attr("data-lazy-img");
            String price = element.getElementsByClass("p-price").first().text();
            String shopName = element.getElementsByClass("p-shop").first().text();
            System.out.println(pict);
            System.out.println(price);
            System.out.println(shopName);
        }
    }
}

网络安全工程师(白帽子)企业级学习路线

第一阶段:安全基础(入门)

img

第二阶段:Web渗透(初级网安工程师)

img

第三阶段:进阶部分(中级网络安全工程师)

img

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

学习资源分享

以下是使用Javajsoup库从京东网站爬取商品图片的代码示例: ```java import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; public class JdImageCrawler { public static void main(String[] args) throws IOException { String url = "https://search.jd.com/Search?keyword=手机"; List<String> imageUrls = getJdImageUrls(url); downloadImages(imageUrls); } /** * 从京东搜索结果页面获取商品图片链接 * @param url 京东搜索结果页面的URL * @return 商品图片链接列表 * @throws IOException */ public static List<String> getJdImageUrls(String url) throws IOException { List<String> imageUrls = new ArrayList<>(); Document doc = Jsoup.connect(url).get(); Elements elements = doc.select(".gl-item .p-img img"); for (Element element : elements) { String imageUrl = element.attr("data-lazy-img"); if (imageUrl == null || imageUrl.isEmpty()) { imageUrl = element.attr("src"); } imageUrls.add(imageUrl.replace("/n9/", "/n1/")); } return imageUrls; } /** * 下载图片到本地 * @param imageUrls 商品图片链接列表 * @throws IOException */ public static void downloadImages(List<String> imageUrls) throws IOException { for (String imageUrl : imageUrls) { URL url = new URL(imageUrl); InputStream is = url.openStream(); String fileName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1); byte[] bytes = new byte[1024]; int len; try (FileOutputStream fos = new FileOutputStream(fileName)) { while ((len = is.read(bytes)) != -1) { fos.write(bytes, 0, len); } } } } } ``` 这个代码示例使用jsoup库从京东搜索结果页面获取商品图片链接,并使用Java标准库下载这些图片到本地。注意,这个示例代码并没有处理异常情况,实际应用中需要加入更多的错误处理和异常处理代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值