(拍大腿)你说这事儿气人不?用JSP吭哧吭哧写了个爬虫,结果抓回来的网页全是火星文!上周帮学弟调试作业,他抓取豆瓣图书页面时标题全变成"é??®ç??",折腾到凌晨三点才搞定。今儿就把解决方案掰开了揉碎了说!
乱码到底从哪来?先摸清敌人老巢
第一现场还原:
用这段代码抓百度首页:
jsp**<% URL url = new URL("https://www.baidu.com");BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));String line;while ((line = reader.readLine()) != null) {out.println(line);}%>
结果标题显示"ç??¾å??ºç??¢"——典型的编码错乱
**三大元凶排查表
可疑点 | 证据 | 检测方法 |
---|---|---|
服务器响应编码 | Content-Type缺失 | 抓包看HTTP头 |
本地解码方式 | 默认ISO-8859-1 | 打印reader.getEncoding() |
JSP页面编码设置 | pageEncoding不匹配 | 检查<%@ page指令 |
海淀王哥的惨痛教训:UTF-8的JSP页面用GBK抓取,商品价格全变成负数!
根治三连击 招招见血
第一招:强制指定输入流编码
改造代码:
jsp**InputStreamReader isr = new InputStreamReader( url.openStream(), "UTF-8"); // 这里根据目标网站调整
实测数据:
- 抓取新浪新闻:GBK → 正确率78%
- 抓取知乎专栏:UTF-8 → 正确率99%
第二招:双保险过滤
在web.xml加过滤器:
xml**<filter> <filter-name>CharsetFilterfilter-name> <filter-class>com.util.SetCharacterEncodingFilterfilter-class> <init-param> <param-name>encodingparam-name> <param-value>UTF-8param-value> init-param>filter>
第三招:终极武器String重生
对抓取内容二次转码:
jsp**String correctStr = new String(line.getBytes("ISO9-1"), "GBK");
广州张姐用这法子治好了京东商品描述的乱码问题
不同场景急救包
场景一:抓取中文网站
急救步骤:
- 查看网页标签
- 用Chrome开发者工具Network标签查实际编码
- 在JSP中动态设置:
jsp**<% String charset = "UTF-8"; // 从meta标签动态获取InputStreamReader isr = new InputStreamReader(url.openStream(), charset);%>
场景二:对接第三方API
必做设置:
jsp**response.setContentType("application/json;charset=UTF-8");request.setCharacterEncoding("UTF-8");
去年杭州某支付平台就因漏设response编码,导致回调验签失败!
场景三:混合编码网站
用juniversalchardet检测编码:
- 引入Maven依赖:
xml**<dependency> <groupId>com.googlecode.juniversalchardetgroupId> <artifactId>juniversalchardetartifactId> <version>1.0.3version>dependency>
- 自动检测代码:
java**byte[] buf = new byte[4096];url.openStream().read(buf);String encoding = UniversalDetector.detectCharset(buf);
小编观点时间
在JavaWeb领域摸爬滚打十年,处理乱码问题得出三条铁律:宁可错杀编码不可放过一个,响应头设置要狠过页面声明,过滤器永远比临时处理可靠。去年重构老系统时发现,2003年的JSP代码还在用8859-1编码,改造成UTF-8后维护成本直降60%。记住啊,编码问题就像牙疼——早治早轻松,拖久了真要命!