文已經(jīng)介紹了ListView和RecyclerView等各種列表控件,在實際的開發(fā)中,會經(jīng)常遇到大批量的數(shù)據(jù)加載和展示的問題,本節(jié)課來具體的學習一下常見的方式和步驟。
移動端和服務器交互一般用得較多的數(shù)據(jù)傳遞方式都是 Json 字符串的形式, 保存對象,我們也可以寫成一個 Json 字符串然后存儲。
常見的解析 Json的方式有Android自帶Json解析器, Gson,F(xiàn)astjson,jackson 等。
通過一個在線網(wǎng)站工具可以實時的實現(xiàn)json數(shù)據(jù)的格式化:http://www.json.cn/
自帶的解析器的API都存在于org.json包下,用到的類有下面這寫:
使用方法參見案例17的原生解析方法,如下:
private List<Lesson> parseJsonByNative(String jsonStr) {
List<Lesson> lessons=new ArrayList<>();
try {
JSONObject jsonObject=new JSONObject(jsonStr);
int code=jsonObject.getInt("status");
if (code !=1) {
return null;
}
JSONArray dataArray=jsonObject.getJSONArray("data");
for (int i=0; i < dataArray.length(); i++) {
JSONObject lessonObject=dataArray.getJSONObject(i);
int id=lessonObject.getInt("id");
String name=lessonObject.getString("name");
String picSmall=lessonObject.getString("picSmall");
String picBig=lessonObject.getString("picBig");
String description=lessonObject.getString("description");
int learner=lessonObject.getInt("learner");
Lesson lesson=new Lesson();
lesson.setId(id);
lesson.setName(name);
lesson.setPicSmall(picSmall);
lesson.setPicBig(picBig);
lesson.setDescription(description);
lesson.setLearner(learner);
?
lessons.add(lesson);
}
} catch (JSONException e) {
e.printStackTrace();
}
return lessons;
}
Gson是google開源的一款用于json解析的庫,受到很多開發(fā)者的喜愛。
Gson在github的開源庫地址:https://github.com/google/gson
在Android中使用gson有兩種方式:
設置依賴后,即可在項目中使用Gson解析數(shù)據(jù),如下所示:
private Lesson[] parseByGson(String jsonStr) {
Gson gson=new Gson();
Type type=new TypeToken<Common<Lesson>>() {
}.getType();
Common<Lesson> common=gson.fromJson(jsonStr, type);
return common.data;
}
fastjson是阿里巴巴團隊開源的一款json解析庫,使用的項目和團隊也很多。在github上的star數(shù)達到了21.2k,超過了gson。
FastJson在復雜類型的Bean轉換Json上會出現(xiàn)一些問題,可能會出現(xiàn)引用的類型,導致Json轉換出錯,需要制定引用。FastJson采用獨創(chuàng)的算法,將parse的速度提升到極致,超過所有json庫。
fastjson開源庫在github的開源地址:https://github.com/alibaba/fastjson
在Android中使用fastjson,需要在項目的build.gradle文件中設置依賴:
compile 'com.alibaba:fastjson:1.1.71.android'
同樣的和gson一樣,也可以下載最新的jar文件,放在android項目的libs目錄中進行依賴設置。
public static List<Lesson> parseByFastJson(String jsonStr) {
com.alibaba.fastjson.JSONObject jsonObject=JSON.parseObject(jsonStr);
com.alibaba.fastjson.JSONArray jsonArray=jsonObject.getJSONArray("data");
return jsonArray.toJavaList(Lesson.class);
}
Jackson是當前用的比較廣泛的,用來序列化和反序列化json的Java開源框架。Jackson是最流行的json解析器之一,Java應用框架中很多都是使用Jackson庫。目前github上Jackson的star數(shù)量達到5.5K。
Jackson在github上的地址如下:https://github.com/FasterXML/jackson
使用Jackson:
此處省略案例,可自行練習。
① 數(shù)據(jù)量小時,可以選擇JSONObject進行處理,要接收代碼量冗余。Gson和FastJson差不多。
② 數(shù)據(jù)量大時,或者數(shù)據(jù)量會有明顯的量級的增加變化,F(xiàn)astJson綜合表現(xiàn)更好。
json數(shù)據(jù)通常都是通過網(wǎng)絡接口請求而來,因此需要進行網(wǎng)絡訪問獲取數(shù)據(jù),包括圖片的加載也是需要網(wǎng)絡的。
使用網(wǎng)絡,需要在AndroidMainfest.xml文件中設置使用網(wǎng)絡權限。
<!--網(wǎng)絡權限-->
<uses-permission android:name="android.permission.INTERNET"/>
在Android P版本開始,為了安全起見,不再允許使用http形式的接口。為了解決這個問題,可以通過在AndroidManifest.xml文件的Application文件中,設施usesCleartextTraffic屬性為true來,表示使用明文網(wǎng)絡流量。推薦還是盡快轉換接口升級為https。
① 在Android中,不能在主線程請求網(wǎng)絡,否則會報錯,網(wǎng)絡請求需要放在工作子線程中。
② 在Android中,請求數(shù)據(jù)完畢,不能在子線程中操作UI,否則會報錯。
圖片加載在android中可以使用比較成熟的開源庫來解決,常用的圖片加載開源庫是Glide,picasso等。
glide在github上的開源地址是:https://github.com/bumptech/glide
使用時首先需要引入glide庫的依賴:
//圖片網(wǎng)絡庫
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
在圖片控件加載的地方,執(zhí)行如下操作:
Glide.with(mContext).load(lesson.getPicBig()).into(holder.imgCover);
picasso在github上的開源地址是:https://github.com/square/picasso
使用時首先需要引入glide庫的依賴:
implementation 'com.squareup.picasso:picasso:2.71828'
在圖片控件加載的地方,執(zhí)行如下操作:
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
與java的基礎相同,HttpURLConnection可以實現(xiàn)網(wǎng)絡請求。具體步驟為:
在Goole I/O 2013上發(fā)布的網(wǎng)絡通信庫,取名為Volley。
Volley的優(yōu)勢及特點是:自動調度網(wǎng)絡請求、支持請求優(yōu)先級、支持取消請求,可以取消單個請求或多個,并且Volley回調時候是在主線程,可以直接操作UI。
Volley庫的操作和使用說明文檔,可以訪問如下地址:https://developer.android.com/training/volley/index.html
implementation 'com.android.volley:volley:1.1.1'
請求之前,首先需要構建RequestQueue請求列隊,全局也只初始化一次就好。
Request請求對象,有StringRequest、ImageRequest、ClearCacheRequest、JsonRequest這四個子類。
可以給Request設置一個tag,并通過RequestQueue.cancelAll(tag)可以進行取消。
第二種方式是使用成熟的網(wǎng)絡請求庫,比如說Okhttp,非常火的一個網(wǎng)絡庫,由Square公司提供。
Okhttp開源庫的github地址如下:https://github.com/square/okhttp
最新的Okhttp庫的版本是4.6.0,在Android應用中使用該庫的操作方法是設置庫依賴,在build.gradle文件中:
implementation("com.squareup.okhttp3:okhttp:4.6.0")
OkHttpClient client=new OkHttpClient();
String run(String url) throws IOException {
Request request=new Request.Builder()
.url(url)
.build();
try (Response response=client.newCall(request).execute()) {
return response.body().string();
}
}
OkHttp庫的請求,回調方法是運行在子線程中,因此不能直接在回調函數(shù)更新ui操作,如果在子線程中操作UI,刷新界面操作,會報如下錯誤:
Only the original thread that created a view hierarchy can touch its views
如果出現(xiàn)該錯誤,可以使用如下的方法解決。該方法用于回到主線程操作UI:
面已經(jīng)介紹了HttpServletResponse響應對象中的一些常用方法,這一小節(jié)介紹如何使用HttpServletResponse響應對象,將結果返回給瀏覽器客戶端。
使用Servlet返回HTML內容給客戶端,是一個比較常見的功能,因為Servlet本來就是用于JavaWeb開發(fā)的,而HTML就是Web開發(fā)的三大核心語言之一。這里給出一個響應HTML內容給客戶端的案例代碼:
package com.gitcode.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @version 1.0.0
* @Date: 2024/2/10 20:20
* @Author ZhuYouBin
* @Description:
*/
public class HtmlResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 響應HTML內容
response.setContentType("text/html;charset=UTF-8");
// 獲取輸出流
PrintWriter writer=response.getWriter();
// 輸出HTML內容
writer.println("<!DOCTYPE html>");
writer.println("<html lang=\"en\">");
writer.println("<head>");
writer.println(" <meta charset=\"UTF-8\">");
writer.println(" <title>響應HTML內容</title>");
writer.println("</head>");
writer.println("<body>");
writer.println(" <h3>Hello World!你好,世界!</h3>");
writer.println("</body>");
writer.println("</html>");
// 關閉流
writer.close();
}
}
運行結果如下所示:
JSON格式在實際的Web開發(fā)中,可以說是最常用的數(shù)據(jù)交互格式啦,在一些前后端分離的項目中,都是采用JSON來進行數(shù)據(jù)交互的,所以這里給出一個響應JSON內容的案例代碼:
package com.gitcode.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @version 1.0.0
* @Date: 2024/2/10 20:20
* @Author ZhuYouBin
* @Description:
*/
public class JsonResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 響應JSON內容
response.setContentType("application/json;charset=UTF-8");
// 獲取輸出流
PrintWriter writer=response.getWriter();
// 輸出JSON內容
writer.println("{");
writer.println(" \"username\":\"名字是Tom-2024\",");
writer.println(" \"password\":\"123456\"");
writer.println("}");
// 關閉流
writer.close();
}
}
運行結果如下所示:
以上,就是使用HttpServletResponse對象返回HTML和JSON數(shù)據(jù)格式。
今天就到這里,未完待續(xù)~~
家好,我是Python進階者。
我們知道再爬蟲的過程中我們對于爬取到的網(wǎng)頁數(shù)據(jù)需要進行解析,因為大多數(shù)數(shù)據(jù)是不需要的,所以我們需要進行數(shù)據(jù)解析,常用的數(shù)據(jù)解析方式有正則表達式,xpath,bs4,這次我們來介紹一下另一個數(shù)據(jù)解析庫--jsonpath,在此之前我們需要先了解一下什么是json。
JSON(JavaScript Object Notation) 是一種輕量級的數(shù)據(jù)交換格式,它使得人們很容易的進行閱讀和編寫。同時也方便了機器進行解析和生成。適用于進行數(shù)據(jù)交互的場景,比如網(wǎng)站前臺與后臺之間的數(shù)據(jù)交互。
Python 2.7及之后版本,自帶了JSON模塊,直接import json就可以使用了。
官方文檔:http://docs.python.org/library/json.html
Json在線解析網(wǎng)站:http://www.json.cn/#
簡介
json簡單說就是javascript中的對象和數(shù)組,所以這兩種結構就是對象和數(shù)組兩種結構,通過這兩種結構可以表示各種復雜的結構;
使用
json模塊提供了四個功能:dumps、dump、loads、load,用于字符串 和 python數(shù)據(jù)類型間進行轉換。
把Json格式字符串解碼轉換成Python對象 從json到python的類型轉化對照如下:
JSON | Python |
object | dict |
array | list |
string | unicode |
number(int) | int,long |
number(real) | float |
true(false) | True(False) |
null | None |
import json
strDict='{"city": "廣州", "name": "小黑"}'
r=json.loads(strDict) # json數(shù)據(jù)自動按Unicode存儲
print(r)
結果如下:
{'city': '廣州', 'name': '小黑'}
讀取文件中json形式的字符串元素 轉化成python類型
import json
s=json.load(open('test.json','r',encoding='utf-8'))
print(s,type(s))
結果如下:
{'city': '廣州', 'name': '小黑'} <class 'dict'>
實現(xiàn)python類型轉化為json字符串,返回一個str對象 把一個Python對象編碼轉換成Json字符串
import json
listStr=[1, 2, 3, 4]
dictStr={"city": "北京", "name": "大貓"}
s1=json.dumps(listStr)
s2=json.dumps(dictStr,ensure_ascii=False)
print(s1,type(s1))
print(s2)
結果如下:
[1, 2, 3, 4] <class 'str'>{"city": "北京", "name": "大貓"} <class 'str'>
注意:
將Python內置類型序列化為json對象后寫入文件
import json
json_info="{'age': '12'}"
file=open('ceshi.json','w',encoding='utf-8')
json.dump(json_info,file)
結果如下:
ceshii,json(目錄文件產(chǎn)生)
JsonPath 是一種信息抽取類庫,是從JSON文檔中抽取指定信息的工具,提供多種語言實現(xiàn)版本,包括:Javascript, Python, PHP 和 Java。
JsonPath 對于 JSON 來說,相當于 XPATH 對于 XML。
下載地址:https://pypi.python.org/pypi/jsonpath
安裝方法:點擊Download URL鏈接下載jsonpath,解壓之后執(zhí)行python setup.py install
官方文檔:http://goessner.net/articles/JsonPath
Json結構清晰,可讀性高,復雜度低,非常容易匹配,下表中對應了XPath的用法。
XPath | JSONPath | 描述 |
/ | $ | 根節(jié)點 |
. | @ | 現(xiàn)行節(jié)點 |
/ | .or[] | 取子節(jié)點 |
.. | n/a | 取父節(jié)點,Jsonpath未支持 |
// | .. | 就是不管位置,選擇所有符合條件的條件 |
* | * | 匹配所有元素節(jié)點 |
@ | n/a | 根據(jù)屬性訪問,Json不支持,因為Json是個Key-value遞歸結構,不需要。 |
[] | [] | 迭代器表示(可以在里邊做簡單的迭代操作,如數(shù)組下標,根據(jù)內容選值等) |
| | [,] | 支持迭代器中做多選。 |
[] | ?() | 支持過濾操作. |
n/a | () | 支持表達式計算 |
() | n/a | 分組,JsonPath不支持 |
我們爬取淘票票官網(wǎng)的城市信息,保存為json文件,進行jsonpath語法測試,獲取所有城市名稱。
請求
import requests
import time
url='https://dianying.taobao.com/cityAction.json?activityId&_ksTS=1632211792156_137&jsoncallback=jsonp138&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36',
}
res=requests.get(url,headers=headers)
result=res.content.decode('utf-8')
print(result) # xxx省略
注意:
headers里面的鍵值對最好都加上,還是有反爬的,該網(wǎng)站,這里為了簡便省去了;
保存數(shù)據(jù)
content=result.split('(')[1].split(')')[0] # 由于文件首尾的字符不需要需要剔除掉做字符串切割
with open('tpp.json','w',encoding='utf-8')as fp:
fp.write(content)
打開json文件如下所示:
解析數(shù)據(jù)
這里我們獲取全部城市名稱
import json
import jsonpath
obj=json.load(open('tpp.json','r',encoding='utf-8')) # 注意,這里是文件的形式,不能直接放一個文件名的字符串
city_list=jsonpath.jsonpath(obj,'$..regionName') # 文件對象 jsonpath語法
print(city_list)
結果如下:
我們知道json是一種常見的數(shù)據(jù)傳輸形式,所以對于爬取數(shù)據(jù)的數(shù)據(jù)解析,json的相關操作是比較重要的,能夠加快我們的數(shù)據(jù)提取效率,本文簡單介紹了json和jsonpath的相關操作,對于測試網(wǎng)站(淘票票)的json做了簡單的數(shù)據(jù)解析,感興趣的小伙伴可以把其他數(shù)據(jù)解析一下。
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。