java获取网页内容
Java里抓网页内容,网页最直接的内容方案就是java.net.http.HttpClient。别去折腾老掉牙的网页HttpURLConnection,那玩意儿写起来像在绣花,内容代码又臭又长。网页JDK 11开始内置的内容HttpClient,同步异步都支持,网页API设计得干净利落,内容这才是网页现代Java该有的样子。
先看最基础的内容一段。你创建一个HttpClient实例,网页构建一个GET请求,内容然后发出去,网页拿到响应体。内容就这么简单,网页十几行代码搞定。
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://example.com")) .GET() .build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); String html = response.body(); 这段代码能跑,但真拿它去抓生产环境的网页,你会被坑哭。别急,我一个个说。
首先是编码问题。很多网站返回的Content-Type头里没有charset,或者干脆写个错的。比如某些老站,页面明明是GBK编码,却告诉你text/html,没charset。你用BodyHandlers.ofString()默认按UTF-8解码,抓回来全是乱码。解决的办法是自己读字节流,然后根据响应头或者页面里的meta标签判断编码。麻烦是麻烦,但这是绕不过去的坎。
HttpResponse<byte[]> resp = client.send(request, HttpResponse.BodyHandlers.ofByteArray()); String charset = "UTF-8"; // 默认 String contentType = resp.headers().firstValue("Content-Type").orElse(""); if (contentType.toLowerCase().contains("charset=")) { charset = contentType.toLowerCase().split("charset=")[1].split(";")[0].trim(); } String html = new String(resp.body(), charset); 再一个坑是重定向。默认HttpClient不跟随重定向,你要么手动设置followRedirects(HttpClient.Redirect.NORMAL),要么自己处理3xx状态码。很多技术博客压根不提这个,结果你抓个短链接,拿到的是一堆重定向响应头,还以为网站改版了。
还有超时。网络请求必须设超时,不然线程能挂到天荒地老。连接超时用connectTimeout(Duration.ofSeconds(5)),读超时在HttpClient里没有直接参数,得靠异步或者底层socket配置。说实话,这块挺烦人的,但你不能不处理。
说到异步,client.sendAsync()返回一个CompletableFuture,配合Java的异步编程模型,抓多个页面可以并行。我写过一个小爬虫,用异步方式同时抓几十个页面,比串行快了一个数量级。不过异步代码调试起来更费劲,新手还是先玩同步吧。
真正让我觉得好用的是Cookie处理。HttpClient的CookieHandler可以让你维持会话状态。有些网站先给你个cookie,你带着再请求才能看到真实内容。这玩意儿在Java里用起来比Python的requests库麻烦,但至少比Apache HttpClient轻量多了。
最后聊点实战经验。抓网页不只是拿HTML字符串,你大概率要解析内容。Java这边我推荐Jsoup,配合HttpClient用,一个负责网络,一个负责解析,分工明确。Jsoup的CSS选择器写起来舒服,比正则硬抠HTML强太多。比如你要抓所有标题,一条doc.select("h2.title").text()就完事了。
我见过很多人写爬虫,一上来就上框架,什么WebMagic、Selenium,其实大部分场景根本用不着。一个HttpClient加Jsoup,轻量、可控、没依赖,跑起来飞快。真要遇到需要JS渲染的页面,再考虑无头浏览器也不迟。
写代码容易,写出能跑的代码也不难,难的是处理好边界情况。字符集、超时、重定向、会话,这四样你心里有数了,抓网页这东西就算入门了。剩下的,就是多抓几个实际网站,踩踩坑,自然就熟了。
(责任编辑:娱乐)













