目录
前言
本文是在看了鸿洋大神微信公众号里的文章后,结合自己的实践写下的一些心得,所以会有很多相同的地方,请别介意仅当做笔记使用。Jsoup的简介什么的就不介绍了,百度一下就可以了。直接从配置和使用开始说起。
文章地址: Android实战——jsoup实现网络爬虫,糗事百科项目的起步
Jsoup配置
在Gradle中添加依赖:
compile 'org.jsoup:jsoup:1.10.2'
并添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
Jsoup使用
Jsoup提供两种网络请求,get和post,使用代码也及其简单,我们首先爬取糗事百科首页的HTML。注意:由于是网络请求操作,必须放在子线程中运行,否则4.4以上的版本会报错。(额,Post我没试成功,不晓得问题在哪,先说Get吧,0.0)
获取HTML网页
- Get方式
new Thread() {
@Override
public void run() {
super.run();
try {
Document defaultDoc = Jsoup.connect("http://www.qiushibaike.com").get();
L.d("一、HTML內容 : " + defaultDoc .toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
- Post方式
new Thread() {
@Override
public void run() {
super.run();
try {
Document doc = Jsoup.connect("http://www.qiushibaike.com/8hr/page/1/")
.data("query", "Java")
.userAgent("Mozilla")
.cookie("auth", "token")
.timeout(3000)
.post();
L.d("一、HTML內容 : " + doc.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
这里对post的参数介绍一下
- connect:设置连接的Url
- data:设置post的键值对数据
- userAgent:设置用户代理(请求头的东西,可以判断你是PC还是Mobile端)
- cookie:设置缓存
- timeout:设置请求超时
- post:发送post请求
获取HTML元素
这里直接说Android端。
1.获取主页数据。
2.封装Bean对象。
3.使用ListView显示数据。
4.利用获取数据中的页码数据做下拉刷新和上拉加载更多操作。
....
剩下的还要做什么,请尽情的发挥你的脑洞吧。
1 获取主页数据
爬取数据利用Jsoup的属性选择器select来实现,具体详细介绍请点击Jsoup中文文档。,这里就不多做介绍。标签的id、class等都可以用作于选择。
通过上图我们可以发现,我们想要获取的数据都有一个共同的class(article)
Document defaultDoc= Jsoup.connect("http://www.qiushibaike.com/").get();
Elements articleEls = defaultDoc.select(".article");
for (int j = 0; j < articleEls.size(); j++) {
Elements authorEls = articleEls.get(j).select(".author");
Elements authorAEls = authorEls.select("a");
Elements authorImgEls = authorAEls.select("img");
L.d("头像" + authorImgEls.attr("src"));
Elements authorH2Els = authorAEls.select("h2");
L.d("作者" + authorH2Els.text());
Elements authorMaleAgeEls = articleEls.get(j).select(".manIcon");
L.d("性别及年龄" + authorMaleAgeEls.text());
Elements authorFemaleAgeEls = articleEls.get(j).select(".womenIcon");
L.d("性别及年龄" + authorFemaleAgeEls.text());
Elements contentEls = articleEls.get(j).select("a.contentHerf");
L.d("内容" + contentEls.text());
L.d("详情Url" + "http://www.qiushibaike.com" + contentEls.attr("href"));
Elements thumbEls = articleEls.get(j).select(".thumb img[src$=jpg]");
L.d("图片内容" + thumbEls.attr("src"));
}
这里使用到的对象
- Document:相当于一个Html文件
- Elements:相当于一个标签的集合
- Element:相当于一个标签
注意Elements与Element的toString()方法和text()方法
- toString():打印出来的是标签的Html内容
- text():打印出来的是标签对应的文本内容
css选择器
- select():获取符合属性选择器要求的标签内容
- getElementById:获取符合ID选择器要求的标签内容
- getElementsByTag:获取符合Tag选择器要求的标签内容
小提示
这里加一点小提示,是在我使用过程中遇到的问题,就当记个笔记。
<div class="articleGender womenIcon">26</div>
<div class="articleGender manIcon">47</div>
如果是这样一个标签有多个class的时候,当我们使用select(“.articleGender”)时是获取不到数据的,只有通过后一个class才能获取数据。(有可能出现这个问题的,只有我一个!0.0原谅我是个渣渣)
2 封装Bean对象
public class JokeBook implements Serializable {
private static final String TAG = "JokeBook";
private String author; // 作者
private String avatar; // 作者头像
private String age; // 作者年龄
private int gender; // 作者性别 0:male(男) 1:female(女)
private String content; // 文字内容
private String thumb; // 图片内容,图片路径
private String godCommentAuthor; // 神评论作者
private String godCommentContent; // 神评论内容
private String godCommentLikeNum; // 点赞数量
private String funnyDegree; // 好笑度
private String commentNum; // 评论次数
private String detailUrl; // 详情Url
}
3 使用ListView显示数据
public class JsoupActivity extends BaseAty implements CommonAdapter.RefreshMoreListener {
@Bind(R.id.jokeLst)
PullToRefreshRecyclerView jokeLst;
private ArrayList<JokeBook> jokes;
private CommonAdapter adapter;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
adapter.notifyDataSetChanged();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jsoup);
ButterKnife.bind(this);
setTitle("Jsoup");
jokes = new ArrayList<>();
RecyclerView mRecyclerView = jokeLst.getRefreshableView();
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
// mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
adapter = new CommonAdapter<JokeBook>(this, R.layout.item_joke_book_layout, jokes) {
@Override
protected void convert(ViewHolder viewHolder, final JokeBook item, int position) {
...
}
};
mRecyclerView.setAdapter(adapter);
initData();
}
private void initData() {
new Thread() {
@Override
public void run() {
super.run();
try {
Document defaultDoc = Jsoup.connect(defaultUrl).get();
setData(defaultDoc);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
private void setData(Document defaultDoc) {
Elements articleEls = defaultDoc.select(".article");
ArrayList<JokeBook> jokeBooksTemp = new ArrayList<>();
for (int j = 0; j < articleEls.size(); j++) {
JokeBook joke = new JokeBook();
Elements authorEls = articleEls.get(j).select(".author");
Elements authorAEls = authorEls.select("a");
Elements authorImgEls = authorAEls.select("img");
if (!authorImgEls.isEmpty()) {
joke.setAvatar(authorImgEls.attr("src"));
}
...
jokes.add(joke);
jokeBooksTemp.add(joke);
}
handler.sendEmptyMessage(0);
}
}
4 利用获取数据中的页码数据做下拉刷新和上拉加载更多操作
由于下拉刷新上拉加载操作都是封装到适配器Adapter中,这里就不多做讲解了,有兴趣了解的朋友可以去看看鸿洋大神的为RecyclerView打造通用Adapter 让RecyclerView更加好用这篇文章,自己学习吧。另外详情页面和主页爬取数据的原理也差不多。
最后上一张成果图吧
这是首页,下图是详情
我觉得该说的都说了,这篇博客也算是写完了,写完后,我一看,我去,发现跟原文没啥区别啊,唉,算了,算了,只是当做笔记使用。另外上面有可能说的不是很详细,可以去看看原文,也可以去看看我的源码,我觉得有的时候看代码比别人给你讲更容易理解。
项目地址:https://github.com/Crazy-L/NdkJniDemo额,由于是我闲着没事儿瞎弄的项目,所以有点乱,具体位置见下图:
写的丑,见笑啦 0.0