在做页面解析时,最大难度在于对动态数据的抓取,特别是由ajax加载的内容。目前对这方面的处理还没很好的解决方案,,虽然有htmlunit之类的模拟浏览器运行工具包,但是其效率以及准确性远远不能满足实际生产的需要。通常情况,我们需要对特定的场景进行特殊性分析、比如,一个商品详细页的加载过程,可能存在向服务端多个http请求。所以我们对商城商品内容的解析过程中,需要对价格等动态加载的内容进一步的获取。下面给大家分享下我抓取京东商城手机频道商品价格的整个过程。以http://item.jd.com/1057746.htm这个链接的商品为例:
商品1057746的详细页
商品1057746源代码的价格代码段
在查看源代码时,发现价格没有内容。这是因为价格内容是通过浏览器解析页面过程,通过js向服务端再次发送请求,根据结果修改html标签内容,达到动态加载加载价格的效果。那么,我们如何才能获取到价格信息呢?
1.首先,使用抓包工具(这里我使用fiddler)抓取访问http://item.jd.com/1057746.html页面所发送出去的所有请求。逐个请求查看其返回的结果,找到返回内容中包含价格信息的请求。请求的链接:http://rs.jd.com/accessorie/newServiceWhite.jsonp?sku=1057746&callback=Recommend.cbNewFittings
2.然后,使用httpclient设置header,模拟浏览器向服务器发送http请求。对返回的结果进行分析,截下价格的那部分,这样就可以得到价格信息。当然,也可以获取其它的数据。
相对应的代码:
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class JDPhonePriceParser {
public static void parserPrice() throws ClientProtocolException, IOException{
CloseableHttpClient httpclient=HttpClients.createDefault();
String url="http://rs.jd.com/accessorie/newServiceWhite.jsonp?sku=1057746&callback=Recommend.cbNewFittings";//这里直接修改sku的值就
// 可以获取其它手机的价格信息
HttpGet httpGet= new HttpGet(url);
httpGet.addHeader("Accept","*/*");
httpGet.addHeader("Accept-Encoding","gzip, deflate");
httpGet.addHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
httpGet.addHeader("User-Agent","Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0");
CloseableHttpResponse response=httpclient.execute(httpGet);
HttpEntity entity=response.getEntity();
String str=EntityUtils.toString(entity);
Pattern p=Pattern.compile("\"price\":\"[0-9]{1,6}.[0-9]{2}\"");
Matcher m=p.matcher(str);
if(m.find()){
String priceStr=m.group(0);
String []array=priceStr.split(":");
if(array!=null&&array.length==2){
System.out.println(array[1].replace("\"", ""));
}
}
}
public static void main(String[]args) throws ClientProtocolException, IOException{
JDPhonePriceParser.parserPrice();
}
}
总结:我们在抓取动态页面时,使用抓包工具分析动态信息所在的url请求,然后采取httpclient获取到所需信息。