使用Jsoup爬取Justdial页面时,获取span标签所有class属性遇阻
解决Jsoup提取span所有class属性时重复获取单一值的问题
嘿,我来帮你排查这个头疼的问题!你说用Jsoup爬Justdial页面时,想获取所有span标签的class属性,结果只拿到一个随机值还重复三次,这大概率是下面几个常见原因导致的,咱们一步步来解决:
可能的原因分析
- 选择器匹配错误:如果你用了像
span.specific-class这种带限定的选择器,只会匹配页面中带有这个class的span元素。如果恰好这个span在页面里重复出现了三次,自然就会得到重复的单一值。 - 未处理多class的情况:很多span标签的class属性是多个值用空格分隔的(比如
class="jd-text jd-bold"),如果直接把整个属性值重复添加,可能会误判为重复;或者你没拆分多class,只拿到了完整的字符串,看起来像是重复。 - 页面动态渲染限制:Justdial的很多内容是通过JavaScript动态加载的,Jsoup只能抓取页面的静态HTML源码,那些动态生成的span标签根本没被抓取到,你看到的重复值可能只是页面加载时就存在的静态span。
- 遍历逻辑出错:比如你在遍历Elements集合时,不小心重复引用了同一个元素,或者循环条件写得有问题,导致同一个元素被处理了三次。
针对性解决方案
方案1:修正Jsoup选择器与遍历逻辑
先确保你能正确抓取所有span标签,并且处理多class的情况,同时用Set自动去重。下面是完整的示例代码:
package scrapers; 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.util.HashSet; import java.util.Set; public class JustdialSpanScraper { public static void main(String[] args) { String targetUrl = "https://www.justdial.com/Indore/Shahi-Bhog-Caterers-Opposite-Sayaji-Behind-Hotel-Park-Vijay-Nagar-Vijay-Nagar/0731PX731-X731-120525133215-B7M1_BZDET?xid=SW5kb3JlIENhdGVyZXJz"; try { // 获取页面静态HTML Document doc = Jsoup.connect(targetUrl).get(); // 选择所有span标签,不要加额外限定 Elements allSpans = doc.select("span"); // 用Set存储class,自动去重 Set<String> allSpanClasses = new HashSet<>(); for (Element span : allSpans) { String classAttr = span.attr("class"); // 跳过没有class属性的span if (classAttr.isEmpty()) continue; // 拆分空格分隔的多个class String[] classList = classAttr.split("\\s+"); for (String singleClass : classList) { allSpanClasses.add(singleClass.trim()); } } // 输出所有去重后的class System.out.println("所有span标签的class属性:"); for (String cls : allSpanClasses) { System.out.println("- " + cls); } } catch (IOException e) { System.err.println("请求页面出错:" + e.getMessage()); e.printStackTrace(); } } }
方案2:处理动态加载内容
如果上面的代码还是只能拿到少量class,说明页面大部分span是动态生成的,这时候需要用Selenium这类工具模拟浏览器加载完整页面。示例代码如下:
package scrapers; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.util.HashSet; import java.util.Set; public class JustdialDynamicScraper { public static void main(String[] args) { String targetUrl = "https://www.justdial.com/Indore/Shahi-Bhog-Caterers-Opposite-Sayaji-Behind-Hotel-Park-Vijay-Nagar-Vijay-Nagar/0731PX731-X731-120525133215-B7M1_BZDET?xid=SW5kb3JlIENhdGVyZXJz"; // 配置ChromeDriver路径,替换成你本地的路径 System.setProperty("webdriver.chrome.driver", "your/path/to/chromedriver.exe"); WebDriver driver = new ChromeDriver(); try { // 模拟浏览器打开页面,等待动态内容加载 driver.get(targetUrl); // 可以加个等待时间,确保内容加载完成(比如3秒) Thread.sleep(3000); // 获取完整的页面源码(包括动态生成的内容) String fullPageSource = driver.getPageSource(); Document doc = Jsoup.parse(fullPageSource); // 后续逻辑和方案1一致 Elements allSpans = doc.select("span"); Set<String> allSpanClasses = new HashSet<>(); for (Element span : allSpans) { String classAttr = span.attr("class"); if (classAttr.isEmpty()) continue; String[] classList = classAttr.split("\\s+"); for (String singleClass : classList) { allSpanClasses.add(singleClass.trim()); } } System.out.println("所有span标签的class属性(含动态内容):"); for (String cls : allSpanClasses) { System.out.println("- " + cls); } } catch (Exception e) { System.err.println("爬取出错:" + e.getMessage()); e.printStackTrace(); } finally { // 关闭浏览器 driver.quit(); } } }
最后检查点
- 先确认你的选择器是
span而不是带有额外限定的选择器,确保能匹配所有span - 检查循环逻辑,避免重复处理同一个元素
- 如果是动态内容问题,必须用浏览器模拟工具才能拿到完整数据
内容的提问来源于stack exchange,提问作者Kushagra Behere
相关产品推荐
相关产品推荐

