您的位置:首页 > 理论基础 > 计算机网络

[Android] - Jsoup实现网络爬虫,获取糗事百科数据

2017-02-20 17:20 549 查看

目录

目录

前言

Jsoup配置

Jsoup使用

前言

本文是在看了鸿洋大神微信公众号里的文章后,结合自己的实践写下的一些心得,所以会有很多相同的地方,请别介意仅当做笔记使用。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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息