精华内容
下载资源
问答
  • JSON三种数据解析方法

    万次阅读 多人点赞 2018-01-15 13:05:01
    引言 JSON数据现在是我们开发中用的最多的,百分之八十的数据都是通过JSON方式进行传输,那么想要学好JSON解析就要了解什么是JSON数据,怎么快速解析它从而提升开发效率。

    JSON数据现在是我们开发中用的最多的,百分之九十的数据都是通过JSON方式进行传输,那么想要学好JSON解析就要了解什么是JSON数据,怎么快速解析它从而提升开发效率。

    1 什么是JSON数据?

    • 先看下面,这里有一段JSON数据,我们根据这段数进行讲解:
    {
      "paramz": {
        "feeds": [
          {
            "id": 299076,
            "oid": 288340,
            "category": "article",
            "data": {
              "subject": "荔枝新闻3.0:不止是阅读",
              "summary": "江苏广电旗下资讯类手机应用“荔枝新闻”于近期推出全新升级换代的3.0版。",
              "cover": "/Attachs/Article/288340/3e8e2c397c70469f8845fad73aa38165_padmini.JPG",
              "pic": "",
              "format": "txt",
              "changed": "2015-09-22 16:01:41"
            }
          }
        ],
        "PageIndex": 1,
        "PageSize": 20,
        "TotalCount": 53521,
        "TotalPage": 2677
      }
    }
    

    其实JSON数据就是一段字符串而已,只不过有不同意义的分隔符将其分割开来而已,我们看上面的符号,里面有[] ,{}等符号,其中

    • 1 []中括号代表的是一个数组;
    • 2 {}大括号代表的是一个对象
    • 3 双引号“”表示的是属性值
    • 4 冒号:代表的是前后之间的关系,冒号前面是属性的名称,后面是属性的值,这个值可以是基本数据类型,也可以是引用数据类型。

    2 了解了JSON数据的格式,怎么对这段数据进行解析呢?

    JSONObject系统自带的解析方式解析,我们先来JSONObject(系统自带的类)类中的方法:

    这里写图片描述

    • 上面用红框框出来的是我们手动解析最常用的方法了,好了,现在我们想要解析上面的一段数据,该怎么做呢?这里我写了一个解析类如下:
    public class JsonUtils {
    
        /**
         * 根据json数据解析返回一个List<HashMap<String, Object>>集合
         * @param json  json数据
         * @return
         */
        public static List<HashMap<String, Object>> getJsonList(String json) {
            List<HashMap<String, Object>> dataList;
            dataList = new ArrayList<>();
            try {
                JSONObject rootObject = new JSONObject(json);
                JSONObject paramzObject = rootObject.getJSONObject("paramz");
                JSONArray feedsArray = paramzObject.getJSONArray("feeds");
                for (int i = 0; i < feedsArray.length(); i++) {
                    JSONObject sonObject = feedsArray.getJSONObject(i);
                    JSONObject dataObject = sonObject.getJSONObject("data");
                    String subjectStr = dataObject.getString("subject");
                    String summaryStr = dataObject.getString("summary");
                    String coverStr = dataObject.getString("cover");
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("subject", subjectStr);
                    map.put("summary", summaryStr);
                    map.put("cover", coverStr);
                    dataList.add(map);
                }
                return dataList;
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    相信很简单一看就懂了吧,此方法写起来主要是比较费时间罢了,无非就是几个方法不停的调用而已,所以显得特别的费时费力,下面我又写了一个解析的方法,方法中会有一些冗余的代码,是为了更加深刻理解JSON解析而写的,实际中可以删掉,也用了一行GSON解析,GSON解析下面会见讲到:

    其中DataModel对象我是将data对象使用GsonFormat插件工具生成的,使用方式可以自行搜索

    public class DataModel {
    
        /**
         * subject : "荔枝新闻3.0:不止是阅读"
         * summary : "江苏广电旗下资讯类手机应用“荔枝新闻”于近期推出全新升级换代的3.0版。"
         * cover : "/Attachs/Article/288340/3e8e2c397c70469f8845fad73aa38165_padmini.JPG"
         * pic :
         * format : video
         * changed : 2015-11-07 14:35:22
         */
    
        public String subject;
        public String summary;
        public String cover;
        public String pic;
        public String format;
        public String changed;
    
        @Override
        public String toString() {
            return "DataModel{" +
                    "subject='" + subject + '\'' +
                    ", summary='" + summary + '\'' +
                    ", cover='" + cover + '\'' +
                    ", pic='" + pic + '\'' +
                    ", format='" + format + '\'' +
                    ", changed='" + changed + '\'' +
                    '}';
        }
    }
    
     /**
         * 根据json对象获取List<DataModel>集合
         * @param json 数据
         * @return
         */
        public static List<DataModel> getGsonList(String json) {
            List<DataModel> dataList;
            try {
                JSONObject rootObject = new JSONObject(json);
                JSONObject paramzObject = rootObject.getJSONObject("paramz");
    
                /**
                 * JSONArray的构造方法获取JSONArray对象
                 */
                JSONArray jsonArray = new JSONArray(paramzObject.getString("feeds"));
                Log.i(TAG, "jsonarray.length():"+jsonArray.length());
    
                /**
                 * 获取JSONObject对象的属性关键字
                 */
                Iterator<String> iterators = paramzObject.keys();
                while (iterators.hasNext()) {
                    Log.i(TAG, "iterators: " + iterators.next());
                }
                JSONArray feeds = paramzObject.getJSONArray("feeds");
                dataList = new ArrayList<>();
                for (int i = 0; i < feeds.length(); i++) {
                    JSONObject jsonObject = feeds.getJSONObject(i);
                    DataModel model = new Gson().fromJson(jsonObject.getString("data"), new TypeToken<DataModel>() {
                    }.getType());
                    Log.i(TAG, "DataModel: " + model.toString());
                    dataList.add(model);
                }
                return dataList;
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            return null;
        }
    

    简单总结一下上面的解析吧:

    1 对于JSONObject对象来说,想要得到一个JSONObject对象通常可以通过

    • (a):构造方式:JSONObject(String json)-> JSONObject rootObject = new JSONObject(json);
    • (b):JSONObject getJSONObject(String name){}-> JSONObject paramzObject = rootObject.getJSONObject(“paramz”);

    2 对于JSONArray对象来说,想要得到一个JSONArray对象通常可以通过

    • (a):构造方式:JSONArray(String json)->JSONArray jsonArray = new JSONArray(paramzObject.getString(“feeds”));
    • (b):JSONObject getJSONObject(String name){}-> JSONArray feeds = paramzObject.getJSONArray(“feeds”);

    3 Gson解析

    我们如果懂得了上面的手动解析方式的话,那么对于Gson解析而言,就太简单了,下面我们就开始解析下面一段JSON数据:

    {
        "homeadlist": [
            {
                "id": 1,
                "imgurl": "/img/homead/a73b3f1d-0f14-429d-9d0f-70643fb0f0eb.jpg",
                "jumpflag": 0,
                "jumpurl": "",
                "posflag": 1,
                "remark": "1111",
                "cityid": 1
            },
            {
                "id": 12,
                "imgurl": "/img/homead/eb442fbf-49db-4ba6-a102-d781505f426d.jpg",
                "jumpflag": 0,
                "jumpurl": "",
                "posflag": 2,
                "remark": "",
                "cityid": 1
            },
            {
                "id": 14,
                "imgurl": "/img/homead/68109460-635d-4c5c-8be8-64d7c7889d18.jpg",
                "jumpflag": 0,
                "jumpurl": "http://shiranlife.kuaizhan.com/",
                "posflag": 4,
                "remark": "",
                "cityid": 1
            }
        ]
    }
    

    首先我们使用GsonFormat工具生成一个类HomeadListModel:

    public class HomeadListModel {
    
        /**
         * code : 1
         * data : {"homeadlist":[{"id":1,"imgurl":"/img/homead/a73b3f1d-0f14-429d-9d0f-70643fb0f0eb.jpg","jumpflag":0,"jumpurl":"","posflag":1,"remark":"1111","cityid":1},{"id":12,"imgurl":"/img/homead/eb442fbf-49db-4ba6-a102-d781505f426d.jpg","jumpflag":0,"jumpurl":"","posflag":2,"remark":"","cityid":1},{"id":14,"imgurl":"/img/homead/68109460-635d-4c5c-8be8-64d7c7889d18.jpg","jumpflag":0,"jumpurl":"http://shiranlife.kuaizhan.com/","posflag":4,"remark":"","cityid":1}]}
         */
    
        public int code;
        public DataBean data;
    
        public static class DataBean {
            public List<HomeadlistBean> homeadlist;
    
            public static class HomeadlistBean {
                public int id;
                public String imgurl;
                public int jumpflag;
                public String jumpurl;
                public int posflag;
                public String remark;
                public int cityid;
            }
        }
    }
    
    

    我们使用OKHttpClient,代码如下

    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    
            Request request = new Request.Builder()
                    .url(url)
                    .get()
                    .build();
    
            builder.build().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Gson gson = new Gson();
                    /**
                     * java.lang.IllegalStateException: closed
                     * 因为OkHttp请求回调中response.body().string()只能有效调用一次
                     *
                     */
    
                    String string = response.body().string();
                    Log.i("aaa", "response: " + string);
                    /**
                     * 重新构建一个response 因为response.body().string()调用一次之后流就断掉了,只能有效调用一次
                     */
                    MediaType mediaType = response.body().contentType();
                    Response response1 = response.newBuilder().body(ResponseBody.create(mediaType, string)).build();
                    String string1 = response1.body().string();
                    Log.i("aaa", "response1: " + string1);
                    /**
                     * 将json数据转换为对象
                     */
                    HomeadListModel model = gson.fromJson(string1, HomeadListModel.class);
                    //HomeadListModel model2 = gson.fromJson(string1, new TypeToken<HomeadListModel>() {
                    }.getType());
                    /**
                     * 将对象转换为json数据
                     */
                    String jsonString = gson.toJson(model);
                    Log.i("aaa", "onResponse2: " + jsonString);
    
                    for (HomeadListModel.DataBean.HomeadlistBean data : model.data.homeadlist) {
                        mData.add(imageUrl + data.imgurl);
                    }
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mAdapter.notifyDataSetChanged();
                        }
                    });
                }
            });
    

    我们想要将一个json数据转换为对象的话需要使用fromJson(String json, Class classOfT) /fromJson(String json, Type typeOfT),当我们需要将对象转换为String的时候根据String toJson(Object src)方法即可。这里需要注意一点,如果response.body().string()调用大于一次的话,就会报错java.lang.IllegalStateException: closed,因为response.body().string()调用一次之后流就断掉了,需要重新构建一个response;


    4 FastJson解析

    • 这个解析和Gson解析差不多,也是一行就搞定了,也是对上面的Gson数据进行解析,想要将json数据解析成对象需要使用 parseObject()方法,参数可以传Class,也可以传Type;当需要通过对象得到String字符串时候使用String json1 = JSONObject.toJSONString(model)即可,下面贴上代码:
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
            Request request = new Request.Builder()
                    .url(url)
                    .get()
                    .build();
            builder.build().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
    
                    String json = response.body().string();
                    /**
                     * 根据json数据获取对象
                     */
                    HomeadListModel model = JSONObject.parseObject(json, new TypeToken<HomeadListModel>() {
                    }.getType());
    //                HomeadListModel model2 = JSONObject.parseObject(json, HomeadListModel.class);
    
                    /**
                     * 根据对象获取json数据
                     */
                    String json1 = JSONObject.toJSONString(model);
                    Log.i("aaa", "fastJson: " + json1);
    
                    for (HomeadListModel.DataBean.HomeadlistBean data : model.data.homeadlist) {
                        mData.add(imageUrl + data.imgurl);
                    }
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mAdapter.notifyDataSetChanged();
                        }
                    });
                }
            });
    

    结尾:上面写了三种解析JSON数据的方法,第一种是最麻烦的,但是不一定是最差的,后面两种Gson和FastJson都是最常用的方法,本博客里面用到的API也是最常用的API,基本开发都够用了,其余未涉及到的请自行查看源码学习吧。


    想要系统学习Android知识体系的,可以免费关注我的博客和Github,你的关注和支持是每一个技术人前进的动力。

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    展开全文
  • scrapy结合selenium解析动态页面

    万次阅读 多人点赞 2020-07-20 21:52:24
    scrapy解决动态页面的一个解决办法,scrapy结合selenium解析动态页面

    scrapy结合selenium解析动态页面

    1. 问题

    虽然scrapy能够完美且快速的抓取静态页面,但是在现实中,目前绝大多数网站的页面都是动态页面,动态页面中的部分内容是浏览器运行页面中的JavaScript脚本动态生成的,爬取相对困难;

    比如你信心满满的写好了一个爬虫,写好了目标内容的选择器,一跑起来发现根本找不到这个元素,当时肯定一万个黑人问号

    于是你在浏览器里打开F12,一顿操作,发现原来这你妹的是ajax加载的,不然就是硬编码在js代码里的,blabla的…

    然后你得去调ajax的接口,然后解析json啊,转成python字典啊,然后才能拿到你想要的东西

    妹的就不能对我们这些小爬爬友好一点吗?

    于是大家伙肯定想过,“为啥不能浏览器看到是咋样的html页面,我们爬虫得到的也是同样的html页面呢? 要是可以,那得多么美滋滋啊”

    2. 解决方案

    既然是想要得到和浏览器一模一样的html页面,那我们就先用浏览器渲染一波目标网页,然后再将浏览器渲染后的html拿给scrapy进行进一步解析不就好了吗

    2.1 获取浏览器渲染后的html

    有了思路,肯定是网上搜一波然后开干啊,搜python操作浏览器的库啊

    货比三家之后,找到了selenium这货

    selenium可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。

    卧槽,这就是我们要的东西啦

    先试一波看看效果如何,目标网址http://quotes.toscrape.com/js/

    别着急,先来看一下网页源码


    我们想要的div.quote被硬编码在js代码中

    用selenium试一下看能不能获取到浏览器渲染后的html

    from selenium import webdriver
    
    # 控制火狐浏览器
    browser = webdriver.Firefox()
    
    # 访问我们的目标网址
    browser.get("http://quotes.toscrape.com/js/")
    
    # 获取渲染后的html页面
    html = browser.page_source
    

    perfect,到这里我们已经顺利拿到浏览器渲染后的html了,selenium大法好啊?

    2.2 通过下载器中间件返回渲染过后html的Response

    这里先放一张scrapy的流程图

    在这里插入图片描述

    所以我们只需要在scrapy下载网页(downloader下载好网页,构造Response返回)之前,通过下载器中间件返回我们自己<通过渲染后html构造的Response>不就可以了吗?

    道理我都懂,关键是在哪一步使用浏览器呢?

    分析:
    (1)我们的scrapy可能是有很多个爬虫的,有些爬虫处理的是纯纯的静态页面,而有些是处理的纯纯的动态页面,又有些是动静态结合的页面(有可能列表页是静态的,正文页是动态的),如果把<浏览器调用代码>放在下载器中间件中,那么除非特别区分哪些爬虫需要selenium,否则每一个爬虫都用selenium去下载解析页面的话,实在是太浪费资源了,就相当于杀鸡用牛刀了,所以得出结论,<浏览器调用代码>应该是放置于Spider类中更好一点;

    (2)如果放置于Spider类中,就意味着一个爬虫占用一个浏览器的一个tab页,如果这个爬虫里的某些Request需要selenium,而某些不需要呢? 所以我们还要在区分一下Request;

    结论:

    1. SeleniumDownloaderMiddleware(selenium专用下载器中间件):负责返回浏览器渲染后的Response
    2. SeleniumSpider(selenium专用Spider):一个spider开一个浏览器
    3. SeleniumRequest:只是继承一下scrapy.Request,然后pass,好区分哪些Request需要启用selenium进行解析页面,相当于改个名

    3. 撸代码,盘他

    3.1 自定义Request

    #!usr/bin/env python  
    # -*- coding:utf-8 _*-
    """ 
    @author:Joshua
    @description:
        只是继承一下scrapy.Request,然后pass,好区分哪些Request需要启用selenium进行解析页面,相当于改个名
    """
    import scrapy
    
    class SeleniumRequest(scrapy.Request):
        """
        selenium专用Request类
        """
        pass
    

    3.2 自定义Spider

    #!usr/bin/env python  
    # -*- coding:utf-8 _*-
    """ 
    @author:Joshua 
    @description:
        一个spider开一个浏览器
    """
    import logging
    import scrapy
    from selenium import webdriver
    
    
    class SeleniumSpider(scrapy.Spider):
        """
        Selenium专用spider
    
        一个spider开一个浏览器
    
        浏览器驱动下载地址:http://www.cnblogs.com/qiezizi/p/8632058.html
        """
        # 浏览器是否设置无头模式,仅测试时可以为False
        SetHeadless = True
    
        # 是否允许浏览器使用cookies
        EnableBrowserCookies = True
    
        def __init__(self, *args, **kwargs):
            super(SeleniumSpider, self).__init__(*args, **kwargs)
            
            # 获取浏览器操控权
            self.browser = self._get_browser()
    
        def _get_browser(self):
            """
            返回浏览器实例
            """
            # 设置selenium与urllib3的logger的日志等级为ERROR
            # 如果不加这一步,运行爬虫过程中将会产生一大堆无用输出
            logging.getLogger('selenium').setLevel('ERROR')
            logging.getLogger('urllib3').setLevel('ERROR')
            
            # selenium已经放弃了PhantomJS,开始支持firefox与chrome的无头模式
            return self._use_firefox()
    
        def _use_firefox(self):
            """
            使用selenium操作火狐浏览器
            """
            profile = webdriver.FirefoxProfile()
            options = webdriver.FirefoxOptions()
            
            # 下面一系列禁用操作是为了减少selenium的资源耗用,加速scrapy
            
            # 禁用图片
            profile.set_preference('permissions.default.image', 2)
            profile.set_preference('browser.migration.version', 9001)
            # 禁用css
            profile.set_preference('permissions.default.stylesheet', 2)
            # 禁用flash
            profile.set_preference('dom.ipc.plugins.enabled.libflashplayer.so', 'false')
            
            # 如果EnableBrowserCookies的值设为False,那么禁用cookies
            if hasattr(self, "EnableBrowserCookies") and self.EnableBrowserCookies:
                # •值1 - 阻止所有第三方cookie。
                # •值2 - 阻止所有cookie。
                # •值3 - 阻止来自未访问网站的cookie。
                # •值4 - 新的Cookie Jar策略(阻止对跟踪器的存储访问)
                profile.set_preference("network.cookie.cookieBehavior", 2)
            
            # 默认是无头模式,意思是浏览器将会在后台运行,也是为了加速scrapy
            # 我们可不想跑着爬虫时,旁边还显示着浏览器访问的页面
            # 调试的时候可以把SetHeadless设为False,看一下跑着爬虫时候,浏览器在干什么
            if self.SetHeadless:
                # 无头模式,无UI
                options.add_argument('-headless')
    
            # 禁用gpu加速
            options.add_argument('--disable-gpu')
    
            return webdriver.Firefox(firefox_profile=profile, options=options)
    
        def selenium_func(self, request):
            """
            在返回浏览器渲染的html前做一些事情
                1.比如等待浏览器页面中的某个元素出现后,再返回渲染后的html;
                2.比如将页面切换进iframe中的页面;
            
            在需要使用的子类中要重写该方法,并利用self.browser操作浏览器
            """
            pass
    
        def closed(self, reason):
            # 在爬虫关闭后,关闭浏览器的所有tab页,并关闭浏览器
            self.browser.quit()
            
            # 日志记录一下
            self.logger.info("selenium已关闭浏览器...")
    
    

    之所以不把获取浏览器的具体代码写在__init__方法里,是因为笔者之前写的代码里考虑过

    1. 两种浏览器的调用(支持firefox与chrome),虽然后来感觉还是firefox比较方便,因为所有版本的火狐浏览器的驱动都是一样的,但是谷歌浏览器是不同版本的浏览器必须用不同版本的驱动(坑爹啊- -’’)
    2. 自动区分不同的操作系统并选择对应操作系统的浏览器驱动

    额… 所以上面spider的代码是精简过的版本

    备注: 针对selenium做了一系列的优化加速,启用了无头模式,禁用了css、flash、图片、gpu加速等… 因为爬虫嘛,肯定是跑的越快越好啦?

    3.3 自定义下载器中间件

    #!usr/bin/env python  
    # -*- coding:utf-8 _*-
    """ 
    @author:Joshua 
    @description:
        负责返回浏览器渲染后的Response
    """
    import hashlib
    import time
    from scrapy.http import HtmlResponse
    from twisted.internet import defer, threads
    from tender_scrapy.extendsion.selenium.spider import SeleniumSpider
    from tender_scrapy.extendsion.selenium.requests import SeleniumRequest
    
    
    class SeleniumDownloaderMiddleware(object):
        """
        Selenium下载器中间件
        """
        
        def process_request(self, request, spider):
            # 如果spider为SeleniumSpider的实例,并且request为SeleniumRequest的实例
            # 那么该Request就认定为需要启用selenium来进行渲染html
            if isinstance(spider, SeleniumSpider) and isinstance(request, SeleniumRequest):
                # 控制浏览器打开目标链接
                browser.get(request.url)
                
                # 在构造渲染后的HtmlResponse之前,做一些事情
                #1.比如等待浏览器页面中的某个元素出现后,再返回渲染后的html;
                #2.比如将页面切换进iframe中的页面;
                spider.selenium_func(request)
                
                # 获取浏览器渲染后的html
                html = browser.page_source
                
                # 构造Response
                # 这个Response将会被你的爬虫进一步处理
                return HtmlResponse(url=browser.current_url, request=request, body=html.encode(), encoding="utf-8")
    

    这里要说一下下载器中间件的process_request方法,当每个request通过下载中间件时,该方法被调用。

    1. process_request() 必须返回其中之一: 返回 None 、返回一个 Response 对象、返回一个 Request 对象或raise IgnoreRequest 。
    2. 如果其返回 Response 对象,Scrapy将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该response。 已安装的中间件的 process_response() 方法则会在每个response返回时被调用。

    更详细的关于下载器中间件的资料 -> https://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/downloader-middleware.html#id2

    3.4 额外的工具

    眼尖的读者可能注意到SeleniumSpider类里有个selenium_func方法,并且在SeleniumDownloaderMiddleware的process_request方法返回Resposne之前调用了spider的selenium_func方法

    这样做的好处是,我们可以在构造渲染后的HtmlResponse之前,做一些事情(比如…那种…很骚的那种…你懂的)

    1. 比如等待浏览器页面中的某个元素出现后,再返回渲染后的html;
    2. 比如将页面切换进iframe中的页面,然后返回iframe里面的html(够骚吗);

    等待某个元素出现,然后再返回渲染后的html这种操作很常见的,比如你访问一篇文章,它的正文是ajax加载然后js添加到html里的,ajax是需要时间的,但是selenium并不会等待所有请求都完毕后再返回

    解决方法:

    1. 您可以通过browser.implicitly_wait(30),来强制selenium等待30秒(无论元素是否加载出来,都必须等待30秒)
    2. 可以通过等待,直到某个元素出现,然后再返回html

    所以笔者对<等待某个元素出现>这一功能做了进一步的封装,代码如下

    #!usr/bin/env python  
    # -*- coding:utf-8 _*-
    """ 
    @author:Joshua 
    @description:
    """
    import functools
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
    
    def waitFor(browser, select_arg, select_method, timeout=2):
        """
        阻塞等待某个元素的出现直到timeout结束
    
        :param browser:浏览器实例
        :param select_method:所使用的选择器方法
        :param select_arg:选择器参数
        :param timeout:超时时间
        :return:
        """
        element = WebDriverWait(browser, timeout).until(
            EC.presence_of_element_located((select_method, select_arg))
        )
    
    
    # 用xpath选择器等待元素
    waitForXpath = functools.partial(waitFor, select_method=By.XPATH)
    
    # 用css选择器等待元素
    waitForCss = functools.partial(waitFor, select_method=By.CSS_SELECTOR)
    

    waitForXpath与waitForCss 是waitFor函数的两个偏函数,意思这两个偏函数是设置了select_method参数默认值的waitFor函数,分别应用不同的选择器来定位元素

    4. 中间件当然要在settings中激活一下

    在这里插入图片描述

    在我们scrapy项目的settings文件中的DOWNLOADER_MIDDLEWARES字典中添加到适当的位置即可

    5. 使用示例

    5.1一个完整的爬虫示例

    # -*- coding: utf-8 -*-
    """
    @author:Joshua
    @description:
        整合selenium的爬虫示例
    """
    import scrapy
    from my_project.requests import SeleniumRequest
    from my_project.spider import SeleniumSpider
    from my_project.tools import waitForXpath
    
    
    # 这个爬虫类继承了SeleniumSpider
    # 在爬虫跑起来的时候,将启动一个浏览器
    class SeleniumExampleSpider(SeleniumSpider):
        """
        这一网站,他的列表页是静态的,但是内容页是动态的
        所以,用selenium试一下,目标是扣出内容页的#content
        """
        name = 'selenium_example'
        allowed_domains = ['pingdingshan.hngp.gov.cn']
        url_format = 'http://pingdingshan.hngp.gov.cn/pingdingshan/ggcx?appCode=H65&channelCode=0301&bz=0&pageSize=20&pageNo={page_num}'
    
        def start_requests(self):
            """
            开始发起请求,记录页码
            """
            start_url = self.url_format.format(page_num=1)
            meta = dict(page_num=1)
            # 列表页是静态的,所以不需要启用selenium,用普通的scrapy.Request就可以了
            yield scrapy.Request(start_url, meta=meta, callback=self.parse)
    
        def parse(self, response):
            """
            从列表页解析出正文的url
            """
            meta = response.meta
            all_li = response.css("div.List2>ul>li")
    
            # 列表
            for li in all_li:
                content_href = li.xpath('./a/@href').extract()
                content_url = response.urljoin(content_href)
                # 内容页是动态的,#content是ajax动态加载的,所以启用一波selenium
                yield SeleniumRequest(url=content_url, meta=meta, callback=self.parse_content)
    
            # 翻页
            meta['page_num'] += 1
            next_url = self.url_format.format(page_num=meta['page_num'])
            # 列表页是静态的,所以不需要启用selenium,用普通的scrapy.Request就可以了
            yield scrapy.Request(url=next_url, meta=meta, callback=self.parse)
    
        def parse_content(self, response):
            """
            解析正文内容
            """
            content = response.css('#content').extract_first()
            yield dict(content=content)
          
        def selenium_func(self, request):
            # 这个方法会在我们的下载器中间件返回Response之前被调用
            
            # 等待content内容加载成功后,再继续
            # 这样的话,我们就能在parse_content方法里应用选择器扣出#content了
            waitForXpath(self.browser, "//*[@id='content']/*[1]")
    
    

    5.2 更骚一点的操作…

    假如内容页的目标信息处于iframe中,我们可以将窗口切换进目标iframe里面,然后返回iframe的html

    要实现这样的操作,只需要重写一下SeleniumSpider子类中的selenium_func方法

    要注意到SeleniumSpider中的selenium_func其实是啥也没做的,一个pass,所有的功能都在子类中重写

    def selenium_func(self, request):
        # 找到id为myPanel的iframe
        target = self.browser.find_element_by_xpath("//iframe[@id='myPanel']")
        # 将浏览器的窗口切换进该iframe中
        # 那么切换后的self.browser的page_source将会是iframe的html
        self.browser.switch_to.frame(target)
    

    6. selenium的一些替代(一些解决动态页面别的方法)

    1. scrapy官方推荐的scrapy_splash
      • 优点
        • 是异步的
        • 可以将部署scrapy的服务器与部署splash的服务器分离开
        • 留给读者遐想的空间
      • 本人觉得的缺点
        • 喂喂,lua脚本很麻烦好吗…(大牛请别打我)
    2. 最新的异步pyppeteer操控浏览器
      • 优点
        • 调用浏览器是异步的,操控的单位是tab页,速度更快
        • 留给读者遐想的空间
      • 本人觉得的缺点
        • 因为pyppeteer是python版puppeteer,所以puppeteer的一些毛病,pyppeteer无可避免的完美继承
        • 笔者试过将pyppeteer整合至scrapy中,在异步中,scrapy跑起来爬虫,总会偶尔timeout之类的…

    anyway,上面两个都是不错的替代,有兴趣的读者可以试一波

    7. scrapy整合selenium的一些缺点

    1. selenium是阻塞的,所以速度会慢些
    2. 对于一些稍微简单的动态页面,最好还是自己去解析一下接口,不要太过依赖selenium,因为selenium带来便利的同时,是更多资源的占用
    3. 整合selenium的scrapy项目不宜大规模的爬取,比如你在自己的机子上写好了一个一个的爬虫,跑起来也没毛病,速度也能接受,然后你很开心地在服务器上部署了你项目上的100+个爬虫(里面有50%左右的爬虫启用了selenium),当他们跑起来的时候,服务器就原地爆炸了… 为啥? 因为相当于服务器同时开了50多个浏览器在跑,内存顶不住啊(土豪忽略…)
    展开全文
  • DNS解析过程

    万次阅读 多人点赞 2019-02-12 14:16:05
    4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。 5、如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地...

    分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.net

    DNS 查询以各种不同的方式进行解析。客户机有时也可通过使用从以前查询获得的缓存信息就地应答查询。DNS 服务器可使用其自身的资源记录信息缓存来应答查询,也可代表请求客户机来查询或联系其他 DNS 服务器,以完全解析该名称,并随后将应答返回至客户机。这个过程称为递归查询。
    另外,客户机自己也可尝试联系其他的 DNS 服务器来解析名称。如果客户机这么做,它会使用基于服务器应答的独立和附加的查询,该过程称作迭代,即DNS服务器之间的交互查询就是迭代查询。
    DNS 查询的过程如下图所示。

    DNS查询过程

    1、在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系。如果有,就先调用这个IP地址映射,完成域名解析。

    2、如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系。如果有,直接返回,完成域名解析。

    3、如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/IP参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器。此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。

    4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。

    5、如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询。如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址(qq.com)给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找qq.com域服务器,重复上面的动作,进行查询,直至找到www.qq.com主机。

    6、如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析。上一级服务器如果不能解析,或找根DNS或把请求转至上上级,以此循环。不管本地DNS服务器是用转发,还是找根DNS,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。

    从客户端到本地DNS服务器是属于递归查询,而DNS服务器之间的交互查询就是迭代查询。

    展开全文
  • Gson 解析教程

    万次阅读 多人点赞 2016-05-18 13:43:38
    Gson 是google解析Json的一个开源框架,同类的框架fastJson,JackJson等等 本人fastJson用了两年,也是从去年才开始接触Gson,希望下面的总结会对博友有用,至于Gson与FastJson的对比,其实半斤八两的问题,不再赘述 第一...

    有部分博友问时间 货币等高级处理 可以参考:时间和货币 框架处理

    且有大量模板 https://github.com/NBXXF/xxf_android/tree/master/xxf_http/src/main/java/com/xxf/arch/json/typeadapter/format/impl/time

     

    Gson 是google解析Json的一个开源框架,同类的框架fastJson,JackJson等等

    本人fastJson用了两年,也是从去年才开始接触Gson,希望下面的总结会对博友有用,至于Gson与FastJson的对比,其实半斤八两的问题,不再赘述

    第一步:在AS下面创建java工程 并添加gson依赖

     

    compile 'com.google.code.gson:gson:2.6.2'

     

     

    Gson的实例化方式:

    1:Gson gson=newGson();

    2:通过GsonBuilder 可以配置多种选项

     

     gson = new GsonBuilder()
                        .setLenient()// json宽松
                        .enableComplexMapKeySerialization()//支持Map的key为复杂对象的形式
                        .serializeNulls() //智能null
                        .setPrettyPrinting()// 调教格式
                        .disableHtmlEscaping() //默认是GSON把HTML 转义的
                        .create();

    Gson的基本用法:

     

     JavaBean转换Json字符串

     gson提供 publicString toJson(Object src) 方法可以将对象转换成jsonStr

      

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 10:39
     */
    public class GsonTest1 {
        public static class Student {
            private String name;
            private int age;
    
            //省略setter getter equals
        }
    
        private static void log(String msg) {
            System.out.println(msg);
        }
    
    
        public static void main(String[] args) throws Exception {
            Gson gson = new Gson();
            Student student = new Student();
            student.setName("xuanyouwu");
            student.setAge(26);
            String jsonStr = gson.toJson(student);
            log("---->javabean convert jsonStr:" + jsonStr);
        }
    
    }
    

     

    运行结果:

    ---->javabean convert jsonStr:{"name":"xuanyouwu","age":26}

     

     

     

        List Map转Json字符串

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 10:39
     */
    public class GsonTest1 {
    
        private static void log(String msg) {
            System.out.println(msg);
        }
    
    
        public static void main(String[] args) throws Exception {
            Gson gson = new Gson();
    
            List<String> list = Arrays.asList("1", "a", "3", "rt", "5");
            log("---->list convert jsonStr:" + gson.toJson(list));
    
            Map<String, Object> content = new HashMap<String, Object>();
            content.put("name", "xuanyouwu");
            content.put("age", "26");
            log("---->map convert jsonStr:" + gson.toJson(content));
        }
    
    }
    
    运行结果:
    ---->list convert jsonStr:["1","a","3","rt","5"]
    ---->map convert jsonStr:{"name":"xuanyouwu","age":"26"}
    

     

     

     

           Json字符串转JavaBean

     

            String studentJsonStr="{\"name\":\"xuanyouwu\",\"age\":26}";
    
            Student student1 = gson.fromJson(studentJsonStr, Student.class);
            log("------->json convert JavaBean:"+student1);


          运行结果:

     

                ------->json convert JavaBean:Student{name='xuanyouwu', age=26}

     

     

       Json字符串转List

     

            String listJsonStr="[\"1\",\"a\",\"3\",\"rt\",\"5\"]";
            Type type = new TypeToken<ArrayList<String>>() {
            }.getType();
            ArrayList<String> sList=gson.fromJson(listJsonStr, type);
            log("------->json convert List:"+sList);
        运行结果:
            ------->json convert List:[1, a, 3, rt, 5]
    </pre><pre code_snippet_id="1687762" snippet_file_name="blog_20160518_11_939636" name="code" class="java">  Gson封装的类型体系
        Gson里面有一个非常有意思的抽象基类JsonElement,他的继承体系:
        <img src="https://img-blog.csdn.net/20160518135136864?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
     JsonObject等同于org的JSONObject,JsonArray也类似,
       JsonNull 其实就是null 字段
         JsonNull jsonNull=new JsonNull();//构造方法过时,推荐INSTANCE

     

     
          JsonNull jsonNull=JsonNull.INSTANCE;
            log("-----"+jsonNull);
       运行结果:
          -----null
    

     

         JsonPrimitive非常有意思,我们知道如果json转换成字符串 可能包含引号的转义,但是通过JsonPrimative我们可以获得为转义的字符串,看实例:

         

    package com.xuan.gson;
    
    import com.google.gson.JsonNull;
    import com.google.gson.JsonPrimitive;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest2 {
        private static void log(String msg) {
            System.out.println(msg);
        }
        public static void main(String[] args) throws Exception {
            String studentJsonStr="{\"name\":\"xuanyouwu\",\"age\":26}";
            log("------>studentJsonStr:"+studentJsonStr);
            JsonPrimitive jsonPrimitive=new JsonPrimitive(studentJsonStr);
            log("------>jsonPrimitive:"+jsonPrimitive);
            log("------>jsonPrimitive:"+jsonPrimitive.toString());
            log("------>jsonPrimitive:"+jsonPrimitive.getAsString());
    
            JsonPrimitive jsonPrimitive2=new JsonPrimitive("this is String");
            log("------>jsonPrimitive2:"+jsonPrimitive2);
            log("------>jsonPrimitive2:"+jsonPrimitive2.toString());
            log("------>jsonPrimitive2:"+jsonPrimitive2.getAsString());
        }
    }
    

     

         运行结果:

    ------>studentJsonStr:{"name":"xuanyouwu","age":26}
    ------>jsonPrimitive:"{\"name\":\"xuanyouwu\",\"age\":26}"
    ------>jsonPrimitive:"{\"name\":\"xuanyouwu\",\"age\":26}"
    ------>jsonPrimitive:{"name":"xuanyouwu","age":26}
    ------>jsonPrimitive2:"this is String"
    ------>jsonPrimitive2:"this is String"
    ------>jsonPrimitive2:this is String

     

     

           创建JsonObject

               通过addPropert(key,value)可以向jsonObject中添加字段 跟hashMap类似

     

            JsonObject jsonObject=new JsonObject();
            jsonObject.addProperty("name","xuanyouwu");
            jsonObject.addProperty("age",26);
            log("------>create jsonObject:"+jsonObject);

                运行结果:

     

                    ------>create jsonObject:{"name":"xuanyouwu","age":26}

     

     

        创建JsonArray       

     

         JsonArray jsonElements=new JsonArray();
            jsonElements.add("a");
            jsonElements.add("b");
            jsonElements.add("c");
            jsonElements.add("d");
            log("------>create jsonArray:"+jsonElements);

              运行结果:

     

              ------>create jsonArray:["a","b","c","d"]

     

     

         JsonObject 嵌套数组或者说嵌套JsonArray

               通过JsonObject的add(key,JsonElement)可以为jsonObject 添加一个数组的字段

     

            JsonObject jsonObject2=new JsonObject();
            jsonObject2.addProperty("name","xuanyouwu");
            jsonObject2.addProperty("age",26);
            JsonArray jsonElements2=new JsonArray();
            jsonElements2.add("骑车");
            jsonElements2.add("打游戏");
            jsonElements2.add("看电视");
            jsonObject2.add("hobby",jsonElements2);
            log("------>create jsonObject inner JsonArray:"+jsonObject2);

               运行结果:

     

                ------>create jsonObject inner JsonArray:{"name":"xuanyouwu","age":26,"hobby":["骑车","打游戏","看电视"]}

     

     

     

    Gson注解

              在Gson中有五类注解

              

     

     

     

              重命名注解:SerializedName 

                 作用:转换关键字key,json转换成JavaBean时,json字段的key 默认必须和我们声明类的字段名称一样,当服务器端返回了关键字怎么办,比如key 为new switch这样,我们    在声明类的时候不能写这样的字段,可能你想服务器端改动,他可能要改数据库,但是我告诉你,做服务端的大部分不愿意改动他的json,是很自私的!这时候重命名注解都排上用场了   第二种场景:服务器端返回的json 的key 简直太丑,或者太长,你想简化,my_parent_name,可以简化成mpn 比较优雅简介

              实例:

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.annotations.SerializedName;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest3 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            public String name;
            public int age;
            @SerializedName("new")
            public int isnew;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        ", isnew=" + isnew +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
    
            String jsonFromServer = "{\n" +
                    "    \"age\": 26,\n" +
                    "    \"name\": \"zhangsan\",\n" +
                    "    \"new\": 1\n" +
                    "}";
            Gson gson = new Gson();
            User user = gson.fromJson(jsonFromServer, User.class);
            log("------>user:" + user);
        }
    }
    

     

    运行结果: ------>user:User{name='zhangsan', age=26, isnew=1}

     

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.annotations.SerializedName;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest3 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User2 {
            public String name;
            public int age;
            @SerializedName("my_parent_name")
            public String pn;
    
            @Override
            public String toString() {
                return "User2{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        ", pn='" + pn + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
            String jsonFromServer2="{\n" +
                    "    \"age\": 26,\n" +
                    "    \"my_parent_name\": \"zhangsanf\",\n" +
                    "    \"name\": \"zhangsan\"\n" +
                    "}";
            Gson gson2 = new Gson();
            User2 user2 = gson2.fromJson(jsonFromServer2, User2.class);
            log("------>user2:" + user2);
        }
    }
    

     

    运行结果: ------>user2:User2{name='zhangsan', age=26, pn='zhangsanf'}

     

     

            作用2:结合alternate 提供多种备用字段key来解析,@SerializedName(value ="desc",alternate = {"other","note"})  如果json中有other就会解析成desc 如果有note也会解析成desc,注意1:value中的值不能出现在alternate中,注意2:alternate的备选字段 会后面的替换前面的

       实例:

       

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.annotations.SerializedName;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest4 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            public String name;
            public int age;
            @SerializedName(value = "desc",alternate = {"other","note"})
            public String desc;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        ", desc='" + desc + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
            String jsonFromServer = "{\n" +
                    "    \"age\": 26,\n" +
                    "    \"other\": \"成都人\",\n" +
                    "    \"name\": \"zhangsan\"\n" +
                    "}";
            Gson gson = new Gson();
            User user = gson.fromJson(jsonFromServer, User.class);
            log("------>user:" + user);
    
    
            String jsonFromServer2 = "{\n" +
                    "    \"age\": 26,\n" +
                    "    \"note\": \"成都人\",\n" +
                    "    \"name\": \"zhangsan\"\n" +
                    "}";
            User user2 = gson.fromJson(jsonFromServer2, User.class);
            log("------>user:" + user2);
    
            //包括desc 与note note在desc之后
            String jsonFromServer3="{\n" +
                    "    \"age\": 26,\n" +
                    "    \"desc\": \"desc成都人\",\n" +
                    "    \"name\": \"zhangsan\",\n" +
                    "    \"note\": \"note成都人\"\n" +
                    "}";
            User user3 = gson.fromJson(jsonFromServer3, User.class);
            log("------>user:" + user3);
    
            //包括desc 与note note在desc之前
            String jsonFromServer4="{\n" +
                    "    \"age\": 26,\n" +
                    "    \"note\": \"note成都人\",\n" +
                    "    \"name\": \"zhangsan\",\n" +
                    "    \"desc\": \"desc成都人\"\n" +
                    "}";
            User user4 = gson.fromJson(jsonFromServer4, User.class);
            log("------>user:" + user4);
        }
    }
    

      运行结果:

     

         ------>user:User{name='zhangsan', age=26, desc='成都人'}
    ------>user:User{name='zhangsan', age=26, desc='成都人'}
    ------>user:User{name='zhangsan', age=26, desc='note成都人'}
    ------>user:User{name='zhangsan', age=26, desc='desc成都人'}

     

     

      Gson @Expose过滤注解 

     

      源码:默认既可以序列化又可以反序列化

     

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Expose {
      
      public boolean serialize() default true;
    
      public boolean deserialize() default true;
    }
    </pre><pre code_snippet_id="1687762" snippet_file_name="blog_20160518_25_4965554" name="code" class="java">可以排除不需要序列化的字段,需要配合GsonBuilder使用
    <pre style="font-family: 宋体; font-size: 9pt; background-color: rgb(255, 255, 255);"><pre name="code" class="java"> Gson gson = new GsonBuilder()
                    .excludeFieldsWithoutExposeAnnotation()
                    .create();

     

     

     

     

     

      不添加@Expose注解的字段将不会解析:
       分为以下几种情况:
        1:不添加@Expose注解等同于@Expose(deserialize = false,serialize = false) 不做任何解析
        2:@Expose(deserialize = true,serialize = false) 只解析用用,也就是反序列化可以,序列化不可以
        3:@Expose(deserialize = false,serialize = true) 序列化可以,反序列化不行
        4:@Expose(deserialize = true,serialize = true) 既可以序列化,也可以反序列化
        实例:将分别演示这四种情况
     
     
     
      不添加@Expose注解:等同于@Expose(deserialize = false,serialize = false)
     
    package com.xuan.gson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; /** * @author xuanyouwu * @email xuanyouwu@163.com * @time 2016-05-18 11:20 */ public class GsonTest5 { private static void log(String msg) { System.out.println(msg); } public static class User { public String name; @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } } public static void main(String[] args) throws Exception { String jsonFromServer = "{\"name\": \"zhangsan\"}"; Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create(); User user = gson.fromJson(jsonFromServer, User.class); log("------>反序列化:" + user); User user1 = new User(); user1.name = "zhangsan2"; String userStr = gson.toJson(user1); log("------>序列化:" + userStr); } } 

     

    运行结果:

     

    ------>反序列化:User{name='null'}
    ------>序列化:{}
    
     
     
     
     
     
      添加@Expose注解 
     
    package com.xuan.gson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.Expose; /** * @author xuanyouwu * @email xuanyouwu@163.com * @time 2016-05-18 11:20 */ public class GsonTest5 { private static void log(String msg) { System.out.println(msg); } public static class User { @Expose //等同于 @Expose(deserialize = true,serialize = true) public String name; @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } } public static void main(String[] args) throws Exception { String jsonFromServer = "{\"name\": \"zhangsan\"}"; Gson gson = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create(); User user = gson.fromJson(jsonFromServer, User.class); log("------>反序列化:" + user); User user1 = new User(); user1.name = "zhangsan2"; String userStr = gson.toJson(user1); log("------>序列化:" + userStr); } } 

     

    运行结果:

     

    ------>反序列化:User{name='zhangsan'}
    ------>序列化:{"name":"zhangsan2"}

     

     

    @Expose注解 只序列化

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.annotations.Expose;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest5 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            @Expose(deserialize = false,serialize = true)
            public String name;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
            String jsonFromServer = "{\"name\": \"zhangsan\"}";
            Gson gson = new GsonBuilder()
                    .excludeFieldsWithoutExposeAnnotation()
                    .create();
            User user = gson.fromJson(jsonFromServer, User.class);
            log("------>反序列化:" + user);
    
            User user1 = new User();
            user1.name = "zhangsan2";
            String userStr = gson.toJson(user1);
            log("------>序列化:" + userStr);
        }
    }
    

     

     

    运行结果:

     

    ------>反序列化:User{name='null'}------>序列化:{"name":"zhangsan2"}

     

     

     

          @Expose 只反序列化

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.annotations.Expose;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest5 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            @Expose(deserialize = true, serialize = false)
            public String name;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
            String jsonFromServer = "{\"name\": \"zhangsan\"}";
            Gson gson = new GsonBuilder()
                    .excludeFieldsWithoutExposeAnnotation()
                    .create();
            User user = gson.fromJson(jsonFromServer, User.class);
            log("------>反序列化:" + user);
    
            User user1 = new User();
            user1.name = "zhangsan2";
            String userStr = gson.toJson(user1);
            log("------>序列化:" + userStr);
        }
    }
    

     

    运行结果:

     ------>反序列化:User{name='zhangsan'}
    ------>序列化:{}

     

     

        @Since(float v)注解  版本控制 

          结合GsonBuilder.setVersion(n)使用 当n>=v时 才会序列化解析

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.annotations.Since;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest6 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            @Since(2)
            public String name;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
            String jsonFromServer = "{\"name\": \"zhangsan\"}";
            Gson gson = new GsonBuilder()
                    .setVersion(1)//版本为1
                    .create();
            User user1 = gson.fromJson(jsonFromServer, User.class);
            log("------>反序列化v=1:" + user1);
    
            User user1_1 = new User();
            user1_1.name = "zhangsan2";
            String userStr = gson.toJson(user1_1);
            log("------>序列化v=1:" + userStr);
    
    
            Gson gson2 = new GsonBuilder()
                    .setVersion(2)//版本为2
                    .create();
            User user2 = gson2.fromJson(jsonFromServer, User.class);
            log("------>反序列化v=2:" + user2);
    
            User user2_1 = new User();
            user2_1.name = "zhangsan2";
            String userStr2_1 = gson2.toJson(user2_1);
            log("------>序列化v=2:" + userStr2_1);
    
            Gson gson3 = new GsonBuilder()
                    .setVersion(3)//版本为3
                    .create();
            User user3 = gson3.fromJson(jsonFromServer, User.class);
            log("------>反序列化v=3:" + user3);
    
            User user3_1 = new User();
            user3_1.name = "zhangsan2";
            String userStr3_1 = gson3.toJson(user3_1);
            log("------>序列化v=3:" + userStr3_1);
        }
    }
    

     

    运行结果:

    ------>反序列化v=1:User{name='null'}
    ------>序列化v=1:{}
    ------>反序列化v=2:User{name='zhangsan'}
    ------>序列化v=2:{"name":"zhangsan2"}
    ------>反序列化v=3:User{name='zhangsan'}
    ------>序列化v=3:{"name":"zhangsan2"}

     

     

        @Util(float v)注解 版本控制

          当gson的setVersion(n) n<v 才解析

     

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.annotations.Until;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest6 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            @Until(2)
            public String name;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws Exception {
            String jsonFromServer = "{\"name\": \"zhangsan\"}";
            Gson gson = new GsonBuilder()
                    .setVersion(1)//版本为1
                    .create();
            User user1 = gson.fromJson(jsonFromServer, User.class);
            log("------>反序列化v=1:" + user1);
    
            User user1_1 = new User();
            user1_1.name = "zhangsan2";
            String userStr = gson.toJson(user1_1);
            log("------>序列化v=1:" + userStr);
    
    
            Gson gson2 = new GsonBuilder()
                    .setVersion(2)//版本为2
                    .create();
            User user2 = gson2.fromJson(jsonFromServer, User.class);
            log("------>反序列化v=2:" + user2);
    
            User user2_1 = new User();
            user2_1.name = "zhangsan2";
            String userStr2_1 = gson2.toJson(user2_1);
            log("------>序列化v=2:" + userStr2_1);
    
            Gson gson3 = new GsonBuilder()
                    .setVersion(3)//版本为3
                    .create();
            User user3 = gson3.fromJson(jsonFromServer, User.class);
            log("------>反序列化v=3:" + user3);
    
            User user3_1 = new User();
            user3_1.name = "zhangsan2";
            String userStr3_1 = gson3.toJson(user3_1);
            log("------>序列化v=3:" + userStr3_1);
        }
    }
    


    运行结果:

     

    ------>反序列化v=1:User{name='zhangsan'}
    ------>序列化v=1:{"name":"zhangsan2"}
    ------>反序列化v=2:User{name='null'}
    ------>序列化v=2:{}
    ------>反序列化v=3:User{name='null'}
    ------>序列化v=3:{}

     

    Gson 高级用法

        相信看过retrofit2.0 源码的同学都知道,其中有一个GsonConverterFactory 里面的用法十分精炼老成,这里来一段源码

     

     

       据说使用TypeAdapter 效率更高,本人还未对比测试,暂时放后吧,TypeAdapter是什么玩意呢?

       在源码中备注了一句 Converts Java objects to and from JSON 就是对象json之间的互相转换 接替了T 泛型类的序列化和反序列化的逻辑

       从源码中我们看到区分了2.1版本之前后之后的用法,2.1版本之前可以自定义adapter:

       

    public class PointAdapter extends TypeAdapter<Point> {
     *     public Point read(JsonReader reader) throws IOException {
     *       if (reader.peek() == JsonToken.NULL) {
     *         reader.nextNull();
     *         return null;
     *       }
     *       String xy = reader.nextString();
     *       String[] parts = xy.split(",");
     *       int x = Integer.parseInt(parts[0]);
     *       int y = Integer.parseInt(parts[1]);
     *       return new Point(x, y);
     *     }
     *     public void write(JsonWriter writer, Point value) throws IOException {
     *       if (value == null) {
     *         writer.nullValue();
     *         return;
     *       }
     *       String xy = value.getX() + "," + value.getY();
     *       writer.value(xy);
     *     }
     *   }}

     

     

     

        使用

      

    GsonBuilder builder = new GsonBuilder();
     *   builder.registerTypeAdapter(Point.class, new PointAdapter());
     *   // if PointAdapter didn't check for nulls in its read/write methods, you should instead use
     *   // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
     *   ...
     *   Gson gson = builder.create();

     

     

     

        在2.1版本之后更推荐直接插入泛型就使用

     

     
    // String json = "{'origin':'0,0','points':['1,2','3,4']}"; // TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class); // Graph graph = graphAdapter.fromJson(json); // }</pre> // And an example for serialization: <pre> {@code // // Graph graph = new Graph(...); // TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class); // String json = graphAdapter.toJson(graph); // }</pre>

     

       实例:使用TypeAdapter 来序列化和反序列化

     

     
    package com.xuan.gson; import com.google.gson.Gson; import com.google.gson.TypeAdapter; /** * @author xuanyouwu * @email xuanyouwu@163.com * @time 2016-05-18 11:20 */ public class GsonTest7 { private static void log(String msg) { System.out.println(msg); } public static class User { public String name; public int age; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public static void main(String[] args) throws Exception { Gson gson = new Gson(); TypeAdapter<User> userTypeAdapter = gson.getAdapter(User.class); User user = new User(); user.name = "xuanyouwu"; user.age = 26; String userJsonStr = userTypeAdapter.toJson(user); log("------>序列化:" + userJsonStr); User user1 = userTypeAdapter.fromJson(userJsonStr); log("------>反序列化:" + user1); } } 
    运行结果:
    ------>序列化:{"name":"xuanyouwu","age":26}
    ------>反序列化:User{name='xuanyouwu', age=26}
    

     

    Gson的容错机制:

     

       为什么要容错了,在javaBean中声明了int类型的age 如果服务端 返回的是"" 空字符串怎么办呢?崩溃?
       如果json格式不规范如 {name=zhangsan,age:26,hobby=null}  发现不是普通的key value
      容错实现方式1:
      1:创建Gson的方式
    gson = new GsonBuilder() .setLenient()// json宽松 .create();

    2:使用JsonReader

       JsonReader jsonReader = gson.newJsonReader(value.charStream());
    jsonReader.<span style="font-family: 宋体; font-size: 9pt;">setLenient(true)</span>

     

        3:自定义TypeAdapter

        4:使用注解JsonAdapter,其实也是自定义Adapter

     

     1.2归为一类 由框架实现,基本json大格式规范,键值对不标准,多引号的问题等等,而不报错停止解析,但是功能相对较弱

     能解决bug 

      

     

    3,4归为一类,都属于自定义adapter,但是3与gson绑定,4使用注解和字段绑定

     实例:

       

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonParseException;
    import com.google.gson.TypeAdapter;
    import com.google.gson.stream.JsonReader;
    import com.google.gson.stream.JsonWriter;
    
    import java.io.IOException;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest8 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            public String name;
            public int age;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
    
    
            ;
        }
    
        public static class UserTypeAdapter extends TypeAdapter<User> {
    
            @Override
            public void write(JsonWriter out, User value) throws IOException {
                out.beginObject();
                out.name("name").value(value.name);
                out.name("age").value(value.age);
                out.endObject();
            }
    
            @Override
            public User read(JsonReader in) throws IOException {
                User user = new User();
                in.beginObject();
                while (in.hasNext()) {
                    switch (in.nextName()) {
                        case "name":
                            user.name = in.nextString();
                            break;
                        case "age":
                            try {
                                String str = in.nextString();
                                user.age = Integer.valueOf(str);
                            } catch (Exception e) {
                            }
                            break;
                    }
                }
                in.endObject();
                return user;
            }
        }
    
        public static void main(String[] args) throws Exception {
            Gson gson = new Gson();
    
            String jsonStrFromServer = "{\n" +
                    "    \"age\": \"\",\n" +
                    "    \"name\": \"zhangsan\"\n" +
                    "}";
            log("------->jsonFromServer:"+jsonStrFromServer);
            try {
                User user = gson.fromJson(jsonStrFromServer, User.class);
                log("------>默认Gson 解析:" + user);
            } catch (JsonParseException e) {//java.lang.NumberFormatException: empty String
                log("------>默认Gson 解析 异常:" + e);
            }
    
            Gson gson2 = new GsonBuilder()
                    .registerTypeAdapter(User.class, new UserTypeAdapter()).create();
            try {
                User user2 = gson2.fromJson(jsonStrFromServer, User.class);
                log("------>自定义adapter 解析:" + user2);
            } catch (JsonParseException e) {//java.lang.NumberFormatException: empty String
                log("------>自定义adapter 异常:" + e);
            }
    
            try {
                UserTypeAdapter userTypeAdapter = new UserTypeAdapter();
                User user3 = userTypeAdapter.fromJson(jsonStrFromServer);
                log("------>自定义adapter 解析2:" + user3);
            } catch (Exception e) {
                log("------>自定义adapter 异常2:" + e);
            }
        }
    }
    

     

    运行结果:

    ------->jsonFromServer:{
        "age": "",
        "name": "zhangsan"
    }
    ------>默认Gson 解析 异常:com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
    ------>自定义adapter 解析:User{name='zhangsan', age=0}
    ------>自定义adapter 解析2:User{name='zhangsan', age=0}

    可以看到 age是空字符串 但是不影响整体的解析流程,这对客户端是十分友好的

     

      基于注解的方式,上面的方式倾向于整体,注解的方式倾向于字段

      

    package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.JsonParseException;
    import com.google.gson.TypeAdapter;
    import com.google.gson.annotations.JsonAdapter;
    import com.google.gson.stream.JsonReader;
    import com.google.gson.stream.JsonWriter;
    
    import java.io.IOException;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest9 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            public String name;
            @JsonAdapter(IntegerTypeAdapter.class)
            public int age;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
    
        public static class IntegerTypeAdapter extends TypeAdapter<Integer> {
    
            @Override
            public void write(JsonWriter out, Integer value) throws IOException {
                out.value(value);
            }
    
            @Override
            public Integer read(JsonReader in) throws IOException {
                int i = 0;
                try {
                    String str = in.nextString();
                    i = Integer.valueOf(str);
                } catch (Exception e) {
                }
                return i;
            }
        }
    
        public static class User2 {
            public String name;
            public int age;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
    
    
        public static void main(String[] args) throws Exception {
            Gson gson = new Gson();
    
            String jsonStrFromServer = "{\n" +
                    "    \"age\": \"\",\n" +
                    "    \"name\": \"zhangsan\"\n" +
                    "}";
            log("------->jsonFromServer:" + jsonStrFromServer);
            try {
                User2 user2 = gson.fromJson(jsonStrFromServer, User2.class);
                log("------>gson 解析:" + user2);
            } catch (Exception e) {
                log("------>gson 解析异常:" + e);
            }
    
    
            try {
                User user = gson.fromJson(jsonStrFromServer, User.class);
                log("------>JsonAdapter 注解 解析:" + user);
            } catch (JsonParseException e) {//java.lang.NumberFormatException: empty String
                log("------>JsonAdapter 注解 异常:" + e);
            }
        }
    }
    

     

     

     

    运行结果:

     

    ------->jsonFromServer:{
        "age": "",
        "name": "zhangsan"
    }
    ------>gson 解析异常:com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
    ------>JsonAdapter 注解 解析:User{name='zhangsan', age=0}
    可以看到我们成功地跳过服务端返回json不合理的坑了吧
    </pre><pre code_snippet_id="1687762" snippet_file_name="blog_20160519_47_1535429" name="code" class="java">不得不吐槽啊,像这种服务器端错误,应该完全归结服务端json不合理返回,
    往往老板都会找客户端原因,怎么又崩溃了?怎么又不显示了?老板不会关心是不是数据返回不合理的问题的!
    做客户端需要相当的承受能力哈,同意的点个赞哈
    </pre><p>其实上面的方式保险是很保险,但是需要维护的地方多,代码量大,我们介绍另外一种方式:JsonSerializer与JsonDeserializer 之关系单方面的处理,可以全局注册某个类型的处理:看实例:</p><p><pre name="code" class="java">package com.xuan.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonDeserializationContext;
    import com.google.gson.JsonDeserializer;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonParseException;
    
    import java.lang.reflect.Type;
    
    /**
     * @author xuanyouwu
     * @email xuanyouwu@163.com
     * @time 2016-05-18 11:20
     */
    public class GsonTest10 {
        private static void log(String msg) {
            System.out.println(msg);
        }
    
        public static class User {
            public String name;
            public int age;
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
    
    
        public static void main(String[] args) throws Exception {
            JsonDeserializer<Integer> jsonDeserializer = new JsonDeserializer<Integer>() {
                @Override
                public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    try {
                        return json.getAsInt();
                    } catch (NumberFormatException e) {
                        return 0;
                    }
                }
            };
            Gson gson = new GsonBuilder()
                    .registerTypeAdapter(int.class, jsonDeserializer)
                    .create();
    
            String jsonStrFromServer = "{\n" +
                    "    \"age\": \"\",\n" +
                    "    \"name\": \"zhangsan\"\n" +
                    "}";
            log("------->jsonFromServer:" + jsonStrFromServer);
            try {
                User user = gson.fromJson(jsonStrFromServer, User.class);
                log("------>  JsonDeserializer<Integer> 解析:" + user);
            } catch (Exception e) {
                log("------>  JsonDeserializer<Integer> 解析异常:" + e);
            }
    
            Gson gson1=new Gson();
            try {
                User user1 = gson1.fromJson(jsonStrFromServer, User.class);
                log("------> 默认gson 解析:" + user1);
            } catch (Exception e) {
                log("------>  默认gson 解析异常:" + e);
            }
    
    
        }
    }
    

    运行结果:

     

    ------->jsonFromServer:{
        "age": "",
        "name": "zhangsan"
    }
    ------>  JsonDeserializer<Integer> 解析:User{name='zhangsan', age=0}
    ------>  默认gson 解析异常:com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String

     这样定义全局的反序列化工具就能避免解析异常

     

     

    展开全文
  • 抖音去水印下载在线解析,我找了好几种方法并亲测,今天汇总一下。哪里方便哪里都可以用 一、方法1 【网页版】:抖音短视频解析下载 - 抖音视频去水印保存到本地 每日解析上限为5次 【链接】:...
  • 做动态域名解析后,主机IP绑定到小明自己的域名,一旦IP地址发生变化,更新域名解析内容,他依旧可以通过域名访问到FTP服务器。 2. 阿杰办理了电信宽带后幸运地发现,获得的IP可以从外网直接访问(之所以说他幸运,...
  • 谷歌地图地理解析

    万次阅读 2020-06-29 17:28:56
    地址解析就是将地址(如:贵州省贵阳市)转换为地理坐标(如经度:106.71,纬度:26.57)的过程。 地理反解析和上面的过程相反是将地理坐标(如纬度:26.57,经度:106.71)转换为地址(中国贵州省贵阳市南明区翠微巷7号 ...
  • Java解析excel工具easyexcel 助你快速简单避免OOM

    万次阅读 多人点赞 2018-07-19 15:03:00
    Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及...
  • 目录argparse介绍argparse使用——代码示例1、创建一个解析器——创建 ArgumentParser() 对象描述description2、添加参数——调用 add_argument() 方法添加参数add_argument() 方法定义如何解析命令行参数3、解析...
  • 常见音频编码格式解析

    万次阅读 多人点赞 2017-12-15 11:22:06
    常见音频编码格式解析常见音频编码格式解析 MP3编码格式 1MP3概述 2MPEG音频压缩基础 3MPEG Layer3编解码的基本原理 4整个MP3文件结构 41ID3V2 42音频数据帧 43ID3v1 AAC编码格式 1AAC概述 2AAC扩展名 3AAC规格 4AAC...
  • 域名解析中的cname解析和显性URL跳转和隐性URL跳转三者有什么区别通俗的来讲,cname解析还是属于dns解析,只是把某个域名解析到另外一个域名对应的某个IP所对应的的空间中,所以需要在服务器端(比如nginx)做域名...
  • 二维码解析

    热门讨论 2014-01-10 21:02:06
    1. 采用 OpenCV + Zbar + Zint 库,绝佳的组合 2. 支持二维码图片解析 3. 支持摄像头采样解析解析速度快,支持范围广 4. 支持二维码图片生成,支持bin格式 5. 支持数据库保存
  • SBJson解析

    千次下载 热门讨论 2012-08-08 15:21:07
    ios SBJson库解析json文件 解析使用
  • Java解析Excel实例解析

    万次阅读 2017-03-09 10:32:55
    Java解析Excel实例解析
  • AVI解析工具,视频解析工具

    热门讨论 2014-06-26 19:03:02
    不错的AVI文件解析具,视频解析工具,亲测可用.
  • 简单使用SAXReader解析xml数据

    万次阅读 多人点赞 2016-12-06 20:13:46
    不过因为工作需求,在对接其他产品的接口时,偶尔会遇到需要使用xml格式数据的情况,所以,也得学学如何解析xml。不过个人感觉,还是Json比较容易些啊,第一次解析xml时,我是一脸懵逼的,不过难者不会,会者不难,...
  • MyBatis二级缓存解析

    万次阅读 2018-08-13 16:14:17
    我们从SqlSessionFactoryBuilder解析mybatis-config.xml配置文件开始: Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new ...
  • 解析函数

    万次阅读 2018-11-22 12:46:44
    文章目录一、解析函数的概念学习目标1、复变函数的导数2、解析函数的概念二、解析函数的充要条件学习目标三、初等函数学习目标 一、解析函数的概念 学习目标 会用求导定义公式求导 函数在一点解析的定义 函数...
  • 地图位置开发解析(一)

    万次阅读 2021-01-12 20:18:07
    地点搜索 逆地址解析 字典分词(词性) 规则 权重值 对分词中 包括行政区划的区分和具体门址地址库 解析 地址解析 路线规划 行政区划 省 市 区 镇 村
  • 本文是一个详细的域名解析教程,以NameSilo为例,分别介绍NameSilo自带的域名解析,以及国外的Cloudflare域名解析与国内的DNSPod域名解析。域名解析介绍域名的NS记录(Name Server)是指处理域名解析的服务器,说白...
  • XML解析之DOM解析详解

    万次阅读 多人点赞 2018-06-05 16:39:34
    Xml解析有两种方式,一种是DOM解析,另一种是SAX解析,两种操作的方式如图。       二、DOM解析   基于DOM解析的xml分析器是将其转换为一个对象模型的集合,用树这种数据结构对信息进行储存。通过DOM...
  • 抖音短视频去水印解析下载教程

    万次阅读 多人点赞 2018-09-11 16:03:17
    下面提到的地址已经停止服务了,新地址1111,方法一样 /3/28/2019 前言 抖音短视频APP里虽然有保存视频的按钮,但这种方式保存的视频右下角有抖音的水印,并且这种方式不适用于电脑。 所以,写这篇文章来分享...
  • DNS正向解析、反向解析、双向解析

    千次阅读 2019-05-16 00:33:25
    资源记录类型: SOA记录(Start Of Authority record...A 记录(Adress record) ##将域名解析到IPv4的IP地址 AAAA 记录(Adress record) ##将域名解析到IPv6的IP位址 CNAME(Canonical Name record) ##别名记录...
  • 给大家分享一个站长需要用的无广告视频解析接口 支持腾讯,优酷,爱奇艺,芒果,乐视,搜狐,视频解析在线播放 肯定很多站长都找这个东西吧 举例说明:比如这个视频解析接口http://ckmov.top/?url= 接口:...
  • django反向解析和正向解析

    千次阅读 2018-03-23 23:22:35
    Django的正向解析和反向解析 先创建一个视图界面 urls.py index.html index页面加载的效果 正向解析 test/?result=1 所谓正向解析就是直接在这里写地址 向urls.py里面一样 例如: test/p1/p2 ...
  • DNS递归解析和迭代解析的区别

    万次阅读 2018-12-02 15:40:55
    11.3.7 DNS递归解析原理 “递归解析”(或叫“递归查询”,其实意思是一样的)是最常见,也是默认的解析方式。在这种解析方式中,如果客户端配置的本地名称服务器不能解析的话,则后面的查询全由本地名称服务器...
  • 文件解析漏洞

    千次阅读 2018-09-25 08:40:27
    文件解析漏洞 IIS解析漏洞 目录解析漏洞(/test.asp/1.jpg) 文件名解析漏洞(test.asp;.jpg) 畸形解析漏洞(test.jpg/*.php) 其他解析漏洞 Ngnix解析漏洞 畸形解析漏洞(test.jpg/*.php) %00空字节代码解析漏洞 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,406,600
精华内容 1,362,640
关键字:

解析