【问题标题】:Scraping A Webpage With JSOUP and Given An SSL Error. Is This A Site Specific Issue? (JSOUP Works On Other Websites)使用 JSOUP 抓取网页并给出 SSL 错误。这是一个特定于站点的问题吗? (JSOUP 在其他网站上工作)
【发布时间】:2021-08-10 20:16:27
【问题描述】:

使用 JSOUP 抓取网页并给出 SSL 错误。这是一个特定于站点的问题吗? (JSOUP 适用于其他网站)

我正在尝试运行一次刮擦,我一直都这样运行刮擦,但这次失败了。 通常我使用jsoup连接到一个网页,然后在页面上抓取我想要的东西。这个似乎正在尝试进行 ssl 握手或其他操作但失败了。

我发现 this page 有类似的问题,但是,我认为该操作在所有 jsoup 刮擦上都有这个问题,我的特定于这个网站。 https://www.strack.de/de/shop/?idm=1162&d=1&idmp=94&spb=MTQ7NzQ7MTI0OzEyMzY7 我在这个网站上尝试了多个页面,都遇到了同样的问题。但是,我尝试过的所有其他网站根本没有这个问题,并且可以正常抓取。

我尝试安装最新版本的java并重新启动电脑,这并没有导致ssl连接成功。我还尝试进入 Firefox 并下载认证。这似乎与答案中描述的路径不同。

“更多信息”>“安全”>“显示证书”>“详细信息”>“导出..”

我认为这个问题可能是由一个单独的问题引起的,因为刮板在其他网站上运行良好。这就是为什么我将其作为一个单独的问题而不是对此问题发表评论的原因。

这是我尝试下载证书时发生的情况。 不是显示证书,而是查看证书,它没有详细信息选项,也没有导出选项。 Trying to get the .cert file, no prompt

我做错了什么会提示握手,或者这是某种不允许在本网站上抓取的功能?我试图从这个网页上刮下价格: https://www.strack.de/de/shop/?idm=1162&d=1&idmp=94&spb=MTQ7NzQ7MTI0OzEyMzY7

我使用 JSOUP 尝试抓取此页面。 它给了我一个错误。当我用谷歌搜索它时,这似乎是人们在尝试连接到服务器时遇到的错误。

它给了我这个错误:

线程“主”javax.net.ssl.SSLHandshakeException 中的异常: sun.security.validator.ValidatorException:PKIX 路径构建失败: sun.security.provider.certpath.SunCertPathBuilderException:无法 在以下位置找到请求目标的有效认证路径 sun.security.ssl.Alerts.getSSLException(Alerts.java:192) 在 sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949) 在 sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) 在 sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) 在 sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509) 在 sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) 在 sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) 在 sun.security.ssl.Handshaker.process_record(Handshaker.java:914) 在 sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) 在 sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) 在 sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) 在 sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) 在 sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) 在 sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) 在 sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153) 在 org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:732) 在 org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:707) 在 org.jsoup.helper.HttpConnection.execute(HttpConnection.java:297) 在 org.jsoup.helper.HttpConnection.get(HttpConnection.java:286) 在 scrapetestforstack.de.ScrapeTestForStackDe.main(ScrapeTestForStackDe.java:81) 引起:sun.security.validator.ValidatorException:PKIX 路径 构建失败: sun.security.provider.certpath.SunCertPathBuilderException:无法 在以下位置找到请求目标的有效认证路径 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387) 在 sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) 在 sun.security.validator.Validator.validate(Validator.java:260) 在 sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) 在 sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) 在 sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) 在 sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491) ... 15 更多原因: sun.security.provider.certpath.SunCertPathBuilderException:无法 在以下位置找到请求目标的有效认证路径 sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) 在 sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) 在 java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) 在 sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) ... 21 更多 C:\Users\LeonardDME\AppData\Local\NetBeans\Cache\8.2\executor-sn-ps\run.xml:53: Java 返回:1 BUILD FAILED(总时间:0 秒)

这是我正在尝试做的代码。


//第 3 阶段抓取 URL 的 URL
文档 doc = Jsoup.connect(URL).get();

   title = doc.title();
                    
         TitleFixer = title.replaceAll(" ", "");
         title = TitleFixer.replaceAll("|", "");
         TitleFixer = title.replaceAll("|", "");
        title = TitleFixer.replaceAll(";", "");
   
  //Set file writing stuff 1
            GimmeAName = ("C:\\Users\\LeonardDME\\Documents\\NetBeansProjects\\ScrapeTestForStackDe\\Urls\\" + title + ".csv");    
    File f = new File(GimmeAName);
    FileWriter fw = new FileWriter(f);
    PrintWriter out = new PrintWriter(fw);    
            StuffToWrite = URLArray[counter];
            // fetch the document over HTTP               
                 Elements spangrabbers = doc.getElementsByClass("art_orginal_preis142790");
                   for (Element spangrab : spangrabbers)
        {
        //System.out.println("New Span: ");
        //System.out.println(spangrab);
        holder2 = spangrab.text();
        //System.out.println(holder2);
        SpanHolderArray[SpanHolderCounter] = holder2;
        SpanHolderCounter++;
        }
            // get all links in page
            Elements links = doc.select("a[href]");
            for (Element link : links) {
                // get the value from the href attribute
                checker = link.attr("href");
                if (checker.contains("http"))
                {
                }
                else if(checker.contains("javascript"))
                {
                }
                else if(checker.contains("style"))
                {
                }
                else
                {
                    counter++;

                    if(LinkContorter == null && LinkContorter.isEmpty())
                    {
                        //do nothing
                    }
                    else
                    {
                        System.out.println(LinkContorter);
                        out.print(LinkContorter);
                        out.print(",");
                        out.print("\n");
                        //Flush the output to the file
                        out.flush();
                    }
                }
            }
            System.out.println(counter);
        //Close the Print Writer
       out.close();       
       //Close the File Writer
       fw.close();

有没有可能你们中的一些人可以尝试抓取这个网站,看看你是否得到和我一样的结果?我怀疑可能有一些防止刮擦的安全措施,但是,除非我确定确实如此,否则我不想放弃这项任务。几个月前,我也曾在 2 月或 3 月抓取过同一个网站,没有任何问题。

【问题讨论】:

    标签: java ssl web-scraping jsoup


    【解决方案1】:

    尽管 Firefox 显示此服务器使用的证书确实使用中间 CA Sectigo RSA Domain Validation Secure Server CA 和根 CA USERTrust RSA Certification Authority 进行验证,但服务器仅发送叶证书而不是标准要求的中间“链”证书。

    您可以通过查看SSLLabs test report 看到这一点;注意摘要中的橙色警告 和证书详细信息框底部附近。或者,如果您拥有(或获得)OpenSSL openssl s_client -connect www.strack.de:443 -showcerts(今天的许多服务器需要 SNI,并且对于低于 1.1.1 的 OpenSSL 来发送 SNI,您需要添加 -servername $host 而不是 this 服务器),或者因为你有 Java keytool -printcert -sslserver www.strack.de

    省略所需的链证书是不费心阅读文档的服务器管理员的常见错误,因为如果他们只使用一两个浏览器进行测试,他们不会注意到错误——浏览器经常可以工作——围绕缺少的链证书,但大多数其他软件,包括 Java,默认情况下要么不能,要么不能。由于它很容易被绕过,因此不太可能将其作为故意的反抓取措施,请参阅下一个,但它确实表明服务器管理员没有实际目标或兴趣来支持协助抓取。

    您可以通过获取链证书来解决此问题,而不是将 所有 证书问题作为suggested by Krystian 来解决——例如通过从 Firefox 导出或通过获取证书 http://crt.sectigo.com/SectigoRSADomainValidationSecureServerCA.crt 中的 caIssuer 链接(显示在 SSLLabs 报告中,或 keytool -printcert 解码,或者如果您将 openssl s_client 输出运行到 openssl x509 -noout -text) - 并将其添加到您的信任库(默认情况下是 $JREDIR/lib/security/cacertsjssecacerts 文件,除非您使用 sysprop 或代码更改它)。

    (已添加)Re Firefox,您已经发现自您链接 Q 以来的几年中 UI 发生了轻微变化:您现在单击挂锁,然后单击右箭头,更多信息,查看证书。要导出特定证书,请单击“Sectigo RSA ...”选项卡并向下滚动大约一半: 然后单击“PEM(cert)”并保存在适当的位置。

    您也可以将此问题报告给网站管理员或所有者。我不知道他们是否会关心您或一般的非浏览器访问。

    【讨论】:

      【解决方案2】:

      如果您不发送任何敏感数据,您可以稍微作弊并配置您自己的 TrustManger 以接受所有数据。

      TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
              return null;
          }
      
          public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
          }
      
          public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
          }
      } };
      
      SSLContext sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new java.security.SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
      

      现在它将用于每个连接,因此不推荐。相反,您可以注释掉最后一行,并通过像这样指定 SSLSocketFactory 使 jsoup 仅将其用于单个连接:

      // HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // not needed anymore
      Document doc = Jsoup.connect(URL)
                          .sslSocketFactory(sc.getSocketFactory())
                          .get();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 2019-09-08
        • 1970-01-01
        • 2021-03-04
        • 2019-04-14
        相关资源
        最近更新 更多