首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >爬取百度指定关键词的TDK

爬取百度指定关键词的TDK

原创
作者头像
技术文章分析
发布2025-09-21 13:51:24
发布2025-09-21 13:51:24
7900
代码可运行
举报
文章被收录于专栏:技术技术
运行总次数:0
代码可运行

以下是实现上述需求的Java代码实践步骤和示例。

1. 技术选型
  • HTTP客户端: OkHttpApache HttpClient。这里使用 OkHttp,因其简洁高效。
  • HTML解析器: Jsoup。它提供了非常方便的API来解析和操作HTML文档。
  • 构建工具: Maven (用于管理依赖)。
2. 添加Maven依赖
代码语言:javascript
代码运行次数:0
运行
复制
xml深色版本<dependencies>
    <!-- OkHttp for HTTP requests -->
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.12.0</version>
    </dependency>
    <!-- Jsoup for HTML parsing -->
    <dependency>
        <groupId>org.jsoup</groupId>
        <artifactId>jsoup</artifactId>
        <version>1.17.2</version>
    </dependency>
</dependencies>
3. 核心代码实现
代码语言:javascript
代码运行次数:0
运行
复制
java深色版本import okhttp3.*;
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.ArrayList;
import java.util.List;
import java.util.Objects;

public class BaiduSERPAnalyzer {

    // OkHttp客户端
    private static final OkHttpClient client = new OkHttpClient();
    // 百度搜索URL模板
    private static final String BAIDU_SEARCH_URL = "https://www.baidu.com/s?wd=%s&pn=%d";
    // 请求头 (模拟浏览器,提高成功率)
    private static final Request.Builder requestBuilder = new Request.Builder()
            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
            .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
            .header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");

    /**
     * 封装网站的TDK信息
     */
    public static class WebsiteInfo {
        public final String title;
        public final String description;
        public final String keywords;
        public final String url;

        public WebsiteInfo(String title, String description, String keywords, String url) {
            this.title = title;
            this.description = description;
            this.keywords = keywords;
            this.url = url;
        }

        @Override
        public String toString() {
            return String.format("Title: %s\nURL: %s\nDescription: %s\nKeywords: %s\n",
                    title, url, description, keywords);
        }
    }

    /**
     * 从百度搜索结果页面解析出目标链接列表
     * @param keyword 搜索关键词
     * @param numPages 要爬取的页数 (每页约10个结果)
     * @return 包含链接的列表
     */
    public static List<String> extractUrlsFromBaidu(String keyword, int numPages) throws IOException {
        List<String> urls = new ArrayList<>();
        String encodedKeyword = java.net.URLEncoder.encode(keyword, "UTF-8");

        for (int page = 0; page < numPages; page++) {
            String url = String.format(BAIDU_SEARCH_URL, encodedKeyword, page * 10);
            Request request = requestBuilder.url(url).build();

            try (Response response = client.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    throw new IOException("Unexpected code " + response);
                }

                String html = Objects.requireNonNull(response.body()).string();
                Document doc = Jsoup.parse(html);

                // 解析百度搜索结果中的链接
                // 百度的搜索结果链接通常在 h3 标签下的 a 标签里,class 可能包含 'title-link' 或类似
                // 注意:百度的HTML结构可能会变,需要根据实际情况调整选择器
                Elements linkElements = doc.select("div.c-container h3 a"); // 这是一个常见选择器,可能需要调整
                for (Element link : linkElements) {
                    String href = link.attr("href");
                    // 百度的链接可能是跳转链接,需要进一步解析真实URL
                    if (href != null && !href.isEmpty() && href.startsWith("http")) {
                        // 如果是直接的外链 (如 ads.baidu.com 可能是广告,需过滤)
                        if (!href.contains("baidu.com") || href.contains("ad.")) {
                            continue;
                        }
                        urls.add(href);
                    } else if (href != null && href.startsWith("/link?url=")) {
                        // 处理百度的跳转链接 /link?url=...
                        String realUrl = resolveBaiduRedirect(href);
                        if (realUrl != null) {
                            urls.add(realUrl);
                        }
                    }
                }
                // 避免过于频繁的请求
                try {
                    Thread.sleep(1000); // 休眠1秒
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
        return urls;
    }

    /**
     * 解析百度跳转链接,获取真实URL
     * @param baiduLink 百度的跳转链接 (如 /link?url=...)
     * @return 真实的目标URL
     */
    private static String resolveBaiduRedirect(String baiduLink) throws IOException {
        // 百度跳转链接通常是相对路径,需要补全
        String fullUrl = "https://www.baidu.com" + baiduLink;
        Request request = requestBuilder.url(fullUrl).build();

        try (Response response = client.newCall(request).execute()) {
            if (response.isRedirect()) {
                // 跟随重定向
                return Objects.requireNonNull(response.request().url()).toString();
            } else {
                // 如果没有重定向,尝试从HTML中解析
                String html = Objects.requireNonNull(response.body()).string();
                Document doc = Jsoup.parse(html);
                Element metaRefresh = doc.selectFirst("meta[http-equiv=refresh]");
                if (metaRefresh != null) {
                    String content = metaRefresh.attr("content");
                    if (content != null) {
                        int pos = content.toLowerCase().indexOf("url=");
                        if (pos != -1) {
                            return content.substring(pos + 4).trim();
                        }
                    }
                }
            }
        }
        return null;
    }
BOLL.PORTASTYL.COM65丨SHARE.NMFZTD.ORG.CN96丨SHARE.PORTASTYL.COM98丨SWEET.PORTASTYL.COM30
ZB.CSWDYS.COM24丨MOBI.SDDANTUOJI.CN26丨WWW.HZBESTSEO.COM97丨ZUQIU.ZYZJZD.CN85
LIVE.CSWDYS.COM35丨PRETTY.JS-SJL.CN10丨IQIYI.PORTASTYL.COM37丨FOOTBALL.NMFZTD.ORG.CN71
TV.CZCJJC.CN90丨M.JS-SJL.CN29丨SOHU.NMFZTD.ORG.CN87丨FREE.CSWDYS.COM47
QQ.XLSY.CN81丨MAP.SDDANTUOJI.CN71丨ONLINE.NMFZTD.ORG.CN13丨ZUQIU.HZBESTSEO.COM71
JRS.NMFZTD.ORG.CN46丨YES.JS-SJL.CN81丨IQIYI.CZCJJC.CN52丨LIVE.NMFZTD.ORG.CN25
24K.XLSY.CN17丨MAP.ZYZJZD.CN71丨SAISHI.CZCJJC.CN29丨JRS.JS-SJL.CN46
ZHIBO.HZBESTSEO.COM36丨MAP.JS-SJL.CN57丨PRETTY.JXLGDL.COM76丨ZYZJZD.CN18
FREE.PORTASTYL.COM18丨MAP.CZCJJC.CN12丨YES.ZYZJZD.CN97丨ZUQIU.PORTASTYL.COM48
ZB.NMFZTD.ORG.CN95丨QQ.SDDANTUOJI.CN37丨MAP.CSWDYS.COM91丨ZB.HZBESTSEO.COM83
    /**
     * 爬取单个网站的 TDK 信息
     * @param url 网站URL
     * @return WebsiteInfo 对象
     */
    public static WebsiteInfo fetchWebsiteTDK(String url) throws IOException {
        Request request = requestBuilder.url(url).build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                System.err.println("Failed to fetch " + url + ": " + response);
                return new WebsiteInfo("", "", "", url);
            }

            String html = Objects.requireNonNull(response.body()).string();
            Document doc = Jsoup.parse(html);

            String title = doc.title(); // 直接获取<title>标签内容
            String description = "";
            String keywords = "";

            // 查找 meta description
            Element descMeta = doc.selectFirst("meta[name='description'], meta[name='Description'], meta[property='og:description']");
            if (descMeta != null) {
                description = descMeta.attr("content");
            }

            // 查找 meta keywords
            Element keywordsMeta = doc.selectFirst("meta[name='keywords'], meta[name='Keywords']");
            if (keywordsMeta != null) {
                keywords = keywordsMeta.attr("content");
            }

            return new WebsiteInfo(title, description, keywords, url);
        }
    }

    /**
     * 主方法:演示完整流程
     */
    public static void main(String[] args) {
        String keyword = "人工智能"; // 替换为你想搜索的关键词
        int pages = 1; // 爬取前1页 (约10个结果)

        try {
            System.out.println("正在搜索关键词: " + keyword);
            List<String> targetUrls = extractUrlsFromBaidu(keyword, pages);
            System.out.println("共找到 " + targetUrls.size() + " 个目标网站链接。");

            // 去重
            targetUrls = new ArrayList<>(new java.util.LinkedHashSet<>(targetUrls));

            List<WebsiteInfo> results = new ArrayList<>();
            for (String url : targetUrls) {
                System.out.println("正在爬取: " + url);
                WebsiteInfo info = fetchWebsiteTDK(url);
                results.add(info);
                // 休眠避免被封
                Thread.sleep(2000);
            }

            // 输出结果
            System.out.println("\n=== 搜索关键词 '" + keyword + "' 的竞品TDK分析结果 ===");
            for (int i = 0; i < results.size(); i++) {
                System.out.println("\n--- 排名 " + (i + 1) + " ---");
                System.out.println(results.get(i));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
4. 重要注意事项与挑战
  1. 反爬虫机制 (Anti-Scraping):
    • IP封禁: 百度会检测并封禁频繁请求的IP。解决方案:使用代理IP池。
    • User-Agent检测: 代码中已设置常见浏览器的User-Agent。
    • 验证码 (CAPTCHA): 如果请求过于频繁,百度会弹出验证码。需要人工干预或使用打码服务,自动化难度高。
    • JavaScript渲染: 百度搜索结果页大量使用JavaScript动态加载。Jsoup 只能解析静态HTML。解决方案:使用 Selenium WebDriver + ChromeDriver 来驱动真实浏览器,但这会显著降低速度和增加复杂性。
  2. HTML结构变化:
    • 百度会不断更新其前端代码。extractUrlsFromBaidu 方法中的CSS选择器 (div.c-container h3 a) 可能失效。需要定期检查并更新选择器。
  3. 链接跳转:
    • 百度的搜索结果链接通常是跳转链接 (/link?url=...)。代码中的 resolveBaiduRedirect 方法通过发起请求并跟随重定向来获取真实URL。这会增加请求次数和时间。
  4. Robots协议与法律风险:
    • 在爬取任何网站前,请检查其 robots.txt 文件(如 https://www.baidu.com/robots.txt)。爬取百度搜索结果可能违反其服务条款。
    • 确保你的行为符合相关法律法规,避免对目标服务器造成过大压力。
  5. 性能与稳定性:
    • 加入 Thread.sleep() 是必要的,但会降低效率。
    • 需要完善的异常处理机制(超时、网络错误、解析错误等)。
5. 替代方案
  • 使用百度提供的API: 百度可能提供官方的搜索API(如百度开放平台),这是最合法、最稳定的方式,但通常有调用次数限制和费用。
  • Selenium: 如前所述,可以处理JavaScript渲染的页面,但资源消耗大。

总结

虽然可以直接用Java+Jsoup+OkHttp实现一个基础的爬虫来获取百度搜索结果中网站的TDK,但面临着反爬虫、动态渲染、法律风险等严峻挑战。对于生产环境或大规模爬取,建议:

  1. 优先考虑官方API。
  2. 如果必须爬取,务必遵守robots.txt,控制请求频率,使用代理IP,并做好被封禁的准备。
  3. 对于JS渲染页面,使用Selenium等工具。

上述代码提供了一个基础框架,但在实际应用中需要根据百度当前的页面结构和反爬策略进行大量的调整和优化。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 技术选型
  • 2. 添加Maven依赖
  • 3. 核心代码实现
  • 4. 重要注意事项与挑战
  • 5. 替代方案
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档