目标是获取新浪新闻如图所示位置的头条新闻数据:
思路是这样的,先访问这个首页拿到这个部分每一条新闻的url,然后再逐一访问这些详情页面,从详情页面获取标题正文图片等数据。
1.通过HttpUrlConection向网页发送数据并分析返回数据:(下面网络操作代码省略子线程和异常捕获)
URL url=new URL("http://news.sina.com.cn/");
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.addRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64)" +
" AppleWebKit/537.36 (KHTML, like Gecko)" +
" Chrome/56.0.2924.87 Safari/537.36");
InputStream input=connection.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(input));
String line;
while ((line=reader.readLine())!=null){
if (line.contains("<h1 data-client=\"headline\">")){
list.add(process2(peocess(line)));
}
}
connection.disconnect();
input.close();
reader.close();
首先,要给connection通过addRequestProperty设置一个代理,否则返回的可能为空或者是一个域名不存在的错误网页。
通过connection的getInputStream拿到流后,包装成BufferedReader,然后就可以通过readLine来逐行读取字符串数据了。
可以在控制台打印每次读取的line,可以发现每一行读取的都是一个完整的标签,对应着xml文件的每一行。
第一行代码中提出的思路是将读取的所有字符串拼接成一个字符串,然后对这个字符串进行逐个节点的解析,通过parser的getEventType判断是否指向首尾标签,拿到我们想要的节点。不过我们这里不需要这么麻烦,通过观察网页的源代码,我们发现我们想要的那几行前面都是
<h1 data-client=\"headline\">
所以只要在读取每一行的时候对是否含有这段文字进行判断就可以了。取到正确的那一行后,再对这一行进行解析。可以看到,这里操作的最终结果是返回一个我自定义的新闻类对象,把这个对象加入数组中。(对象含有标题,正文和图片Bitmap三个字段)下面就是如何生成这个对象:
2.解析上面拿到的那行xml,返回新闻详情页的地址:
private String peocess(String result) {//解析XML得到新闻的地址
String address=null;
try {
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser parser=factory.newPullParser();
parser.setInput(new StringReader(result));
parser.next();
parser.next();//到达a标签
address=parser.getAttributeValue(1);//第二个属性
parser.next();//到达标题
String title=parser.getText();
} catch (Exception e) {
e.printStackTrace();
}
return address;
}
这里使用了Pull方式进行解析,核心的解析工具就是这个parser对象。这个对象通过setInput接收一个输入流,然后对这个流进行解析,这里包装后传入了字符串流。
获取parser中的数据主要通过他的getNextText,getText,getName,getEventType,getAttrribute...几个方法。parser可以拿到当前节点的标签名,类型,文字,属性。
parser.next也就是向后移动,但是这里并不是移动到下一个节点。比如我这里解析的这一行,他是一个h1标签包住一个a标签,链接在a的属性里,标题被a包住。
调用第一个next,parser指向h1首标签,再移动,指向a的首标签,这时候可以通过getAttributeValue拿到链接。再往下走就是标题文本了,用getText拿出即可。
3.解析新闻详情页,生成新闻对象:
public NewsItem process2(String address){//解析地址生成一个新闻对象
ItemPass pass=new ItemPass(null,null,null);
NewsItem item=new NewsItem(null,null,null);
try {
URL url=new URL(address);
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.addRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64)" +
" AppleWebKit/537.36 (KHTML, like Gecko)" +
" Chrome/56.0.2924.87 Safari/537.36");
InputStream input=connection.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(input));
String line;
StringBuilder builder=new StringBuilder();
while ((line=reader.readLine())!=null){
if (line.contains("<title>")){//找到新闻标题
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser parser=factory.newPullParser();
parser.setInput(new StringReader(line+"/n"));
parser.next();
String s=parser.nextText();
item.setTitle(s);
pass.setTitle(s);
}
if (line.contains("<p> ")){//找到文章内容
if (!line.contains("<s") &&!line.contains("<a")){
if (line.contains(" ")){
line.replace(" "," ");
}
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser parser=factory.newPullParser();
parser.setInput(new StringReader(line));
parser.next();
parser.next();//到达文字内容
builder.append(parser.getText()+"\n");
}
}
if (line.contains("<div class=\"img_wrapper\"><img src=")){
Log.v("tag",line);
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser parser=factory.newPullParser();
parser.setInput(new StringReader(line));
parser.next();
parser.next();//到达img标签
String imgAdress=parser.getAttributeValue(0);
pass.setAddress(imgAdress);
item.setImage(Tool.urlToBitmap(imgAdress));
}
}
String s=builder.toString();
item.setContent(s);
pass.setContent(s);
connection.disconnect();
input.close();
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
list2.add(pass);
return item;
}
可以看到解析思路和上面是一样的,通过特定的文字字段匹配拿到标题,正文,和图片。正文有很多,要拼接起来。
4.实现效果:(注意有些新闻没有图片,注意空指针,没有图片的我都用了别的图片代替):