使用Pull解析XML获取新浪新闻

news/2024/7/3 12:06:10

目标是获取新浪新闻如图所示位置的头条新闻数据:

思路是这样的,先访问这个首页拿到这个部分每一条新闻的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.实现效果:(注意有些新闻没有图片,注意空指针,没有图片的我都用了别的图片代替):

                                       



http://www.niftyadmin.cn/n/4646368.html

相关文章

位运算记录

作为在互联网领域工作的程序员啊&#xff0c;我们需要不断地学习。自己也坚持每天刷一两个 LeetCode 题目&#xff0c;在刷题的过程中&#xff0c;发现有不少题目都涉及到一些位运算的知识&#xff0c;这篇文章记录一下。 介绍运算 按位与(&)按位或(|)按位异或(^)左移(<…

只手遮天

.. 用这个作为这~ 一连5篇的结束 .. 有感而发&#xff0c;写段文字 .. 读大学时&#xff0c;自我感觉不太会说话&#xff0c;显得相当的木纳&#xff0c;对许多人除了微笑讲不上几句 .. 如今&#xff0c;已经会说话&#xff0c;而且也会分场合 .. 说话时&#xff0c;我的话仍然…

spring boot 开启https

1.生成证书 keytool -genkey -alias tomcat -keyalg RSA -keystore E:/https.keystore将生成好的证书放在项目根目录即可 2 修改配置文件 server:port: 443servlet:context-path: /tomcat:uri-encoding: UTF-8max-threads: 1000min-spare-threads: 30ssl:#生成证书的名字key-st…

从github上的优秀实例看MVP模式

github上有一个关于MVP模式学习的实例https://github.com/antoniolg/androidmvp&#xff0c;虽然只有简单的几个类&#xff0c;却收获了几千个星。这个例子确实通俗易懂&#xff0c;直观的体现出了MVP模式的特点&#xff1a; 考虑这样一个需求&#xff0c;页面显示一个列表&…

显著减少项目gradle编译时间

原文来自https://zeroturnaround.com/rebellabs/making-gradle-builds-faster/ 1.对build过程进行配置实现编译优化&#xff1a; &#xff08;1&#xff09;首先了解如何用命令行进行编译&#xff1a; 使用git命令行进入项目根目录&#xff0c;然后执行 ./gradlew :app:asse…

CVE-2018-12613(远程文件包含)

问题在index.php的55~63行// If we have a valid target, lets load that script instead if (! empty($_REQUEST[target])&& is_string($_REQUEST[target])&& ! preg_match(/^index/, $_REQUEST[target])&& ! in_array($_REQUEST[target], $target_bl…

Support Design库中的BottomSheetDialog组件使用

首先来看这个组件使用的经典案例&#xff0c;微信公众号文章操作功能显示&#xff1a; 首先要知道BottomSheetDialog有两种&#xff0c;第一种弹出后不影响主界面交互&#xff0c;第二种弹出后主界面变暗不能交互&#xff0c;这里分别进行使用。 1.首先是普通的BottomSheetDia…

Netty内存池ByteBuf 内存回收

内存池ByteBuf 内存回收: 在前面的章节中我们有提到, 堆外内存是不受JVM 垃圾回收机制控制的, 所以我们分配一块堆外内存进行ByteBuf 操作时, 使用完毕要对对象进行回收, 本节就以PooledUnsafeDirectByteBuf 为例讲解有关内存分配的相关逻辑。PooledUnsafeDirectByteBuf 中内存…