更新书源

pull/5/head
fengyuecanzhu 4 years ago
parent 947a87bf25
commit be25d5569b
  1. 9
      README.md
  2. 23
      app/src/main/assets/updatelog.fy
  3. 5
      app/src/main/java/xyz/fycz/myreader/application/SysManager.java
  4. 2
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  5. 6
      app/src/main/java/xyz/fycz/myreader/enums/BookSource.java
  6. 1
      app/src/main/java/xyz/fycz/myreader/model/SearchEngine.java
  7. 6
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  8. 98
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  9. 25
      app/src/main/java/xyz/fycz/myreader/webapi/CommonApi.java
  10. 23
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/Ben100ReadCrawler.java
  11. 28
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/BiJianReadCrawler.java
  12. 31
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/BiQuGe44ReadCrawler.java
  13. 60
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/CansShu99ReadCrawler.java
  14. 32
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ChuanQiReadCrawler.java
  15. 16
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/DSTQReadCrawler.java
  16. 30
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/Du1DuReadCrawler.java
  17. 151
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/EWenXueReadCrawler.java
  18. 68
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/HongChenReadCrawler.java
  19. 48
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/JiuTaoReadCrawler.java
  20. 32
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/LaoYaoReadCrawler.java
  21. 24
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/LiuLangCatReadCrawler.java
  22. 172
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/LuoQiuReadCrawler.java
  23. 16
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/MiQuReadCrawler.java
  24. 54
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/MiaoBiReadCrawler.java
  25. 22
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/PiaoTianReadCrawler.java
  26. 21
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/PinShuReadCrawler.java
  27. 20
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/PinShuReadCrawler2.java
  28. 34
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/QB5ReadCrawler.java
  29. 23
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/QiQiReadCrawler.java
  30. 24
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/QuanNovelReadCrawler.java
  31. 32
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ReXueReadCrawler.java
  32. 32
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ShiGuangReadCrawler.java
  33. 178
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ShuHaiGeReadCrawler.java
  34. 24
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/SoNovelReadCrawler.java
  35. 29
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/TianLaiReadCrawler.java
  36. 40
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/WoLongReadCrawler.java
  37. 146
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XBiQuGeReadCrawler.java
  38. 50
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XS7ReadCrawler.java
  39. 172
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XS7ReadCrawler2.java
  40. 68
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XiaGuReadCrawler.java
  41. 48
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/XingXingReadCrawler.java
  42. 109
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/YanQingLouReadCrawler.java
  43. 57
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/YunZhongReadCrawler.java
  44. 170
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ZW37ReadCrawler.java
  45. 161
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ZaiShuYuanReadCrawler.java
  46. 16
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/read/ZuoPinReadCrawler.java
  47. 2
      app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java
  48. 37
      app/src/main/java/xyz/fycz/myreader/widget/page/NetPageLoader.java
  49. 108
      app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java
  50. 286
      app/src/main/res/layout/activity_search_book.xml
  51. 6
      app/src/main/res/menu/menu_search.xml
  52. 7
      app/src/main/res/values/strings.xml
  53. 10
      app/src/main/resources/crawler.properties
  54. 4
      app/version_code.properties

@ -2,21 +2,22 @@
风月读书,一款开源、无广告的小说阅读软件。
成品下载(v1.8.1):[https://fycz.lanzous.com/i5vu3l6pcuj](https://fycz.lanzous.com/i5vu3l6pcuj)
成品下载(v1.8.2):[https://fycz.lanzous.com/iEy9kldwrpi](https://fycz.lanzous.com/iEy9kldwrpi)
[更新日志](./app/src/main/assets/updatelog.fy)
#### 一、关于书源
* 软件内置了~~28~~(25)个书源如下:
* 软件内置了~~36~~(33)个书源如下:
* ~~26~~(23)个网络小说书源:天籁小说、笔趣阁44、~~品书网~~、笔趣阁、
* ~~32~~(29)个网络小说书源:天籁小说、笔趣阁44、~~品书网~~、笔趣阁、
全本小说、米趣小说、九桃小说、云中书库、
搜小说网、全小说网、~~奇奇小说~~、妙笔阁、
丹书铁券、小说旗、读一读网、飘天文学、
老幺小说、星星小说、时光小说、峡谷文学、
红尘小说、~~热血小说~~、传奇小说、笔尖小说、
言情楼、卧龙小说
言情楼、卧龙小说、E文学、书海阁、落秋中文、
三七中文、新笔趣阁、斋书苑
* 4个实体书书源:超星图书·实体、作品集·实体、99藏书·实体、100本·实体
* 如何自行制作并添加书源.

@ -1,7 +1,24 @@
风月读书v1.8.2
风月读书v1.8.3
1、优化阅读体验
2、修复已知bug
3、支持分享本地书籍(txt)
2020.02.06
风月读书v1.8.2
更新内容:
1、新增书源:E文学、书海阁、落秋中文、三七中文、新笔趣阁、斋书苑
2、修复书源:天籁小说、小说旗
3、优化阅读体验
4、修复已知bug
5、支持分享本地书籍(txt)
公告:
2021.02.06:
昨天应该是某站打击盗版导致许多小说网站被墙,书籍无法更新或加载,
您可通过科学上网或换源来获取书籍内容,或者等待网站恢复后更新软件。
被墙的书源网站:天籁小说、笔趣阁44、全本小说、米趣小说、九桃小说、
云中书库、小说旗、老幺小说、传奇小说、星星小说
当前已恢复的网站:天籁小说、小说旗(需要更新软件)
2020.02.01
风月读书v1.8.1

@ -126,6 +126,11 @@ public class SysManager {
ReadCrawlerUtil.removeReadCrawler("qiqi", "rexue", "pinshu");
ReadCrawlerUtil.addReadCrawler(BookSource.bijian, BookSource.yanqinglou, BookSource.wolong);
Log.d("SourceVersion", "" + 4);
case 5:
ReadCrawlerUtil.addReadCrawler(BookSource.ewenxue, BookSource.shuhaige,
BookSource.luoqiu, BookSource.zw37, BookSource.xbiquge,
BookSource.zaishuyuan);
Log.d("SourceVersion", "" + 5);
}
setting.setSourceVersion(APPCONST.SOURCE_VERSION);
saveSetting(setting);

@ -83,7 +83,7 @@ public class APPCONST {
//设置版本号
public static final int SETTING_VERSION = 11;
public static final int SOURCE_VERSION = 5;
public static final int SOURCE_VERSION = 6;
public static final String FORMAT_FILE_DATE = "yyyy-MM-dd";

@ -37,6 +37,12 @@ public enum BookSource {
bijian(MyApplication.getApplication().getString(R.string.read_bijian)),
yanqinglou(MyApplication.getApplication().getString(R.string.read_yanqinglou)),
wolong(MyApplication.getApplication().getString(R.string.read_wolong)),
ewenxue(MyApplication.getApplication().getString(R.string.read_ewenxue)),
shuhaige(MyApplication.getApplication().getString(R.string.read_shuhaige)),
luoqiu(MyApplication.getApplication().getString(R.string.read_luoqiu)),
zw37(MyApplication.getApplication().getString(R.string.read_zw37)),
xbiquge(MyApplication.getApplication().getString(R.string.read_xbiquge)),
zaishuyuan(MyApplication.getApplication().getString(R.string.read_zaishuyuan)),
chaoxing(MyApplication.getApplication().getString(R.string.read_chaoxing)),
zuopin(MyApplication.getApplication().getString(R.string.read_zuopin)),
cangshu99(MyApplication.getApplication().getString(R.string.read_cangshu99)),

@ -61,6 +61,7 @@ public class SearchEngine {
* 搜索引擎初始化
*/
public void initSearchEngine(@NonNull List<ReadCrawler> sourceList) {
mSourceList.clear();
mSourceList.addAll(sourceList);
executorService = Executors.newFixedThreadPool(threadsNum);
scheduler = Schedulers.from(executorService);

@ -226,7 +226,7 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
break;
case 7:
ToastUtils.showWarring("无网络连接!");
mPageLoader.chapterError();
mPageLoader.chapterError("无网络连接!");
break;
case 8:
binding.pbLoading.setVisibility(View.GONE);
@ -235,10 +235,6 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
ToastUtils.showInfo("正在后台缓存书籍,具体进度可查看通知栏!");
notificationUtil.requestNotificationPermissionDialog(ReadActivity.this);
break;
case 10:
if (mPageLoader != null) {
mPageLoader.chapterError();
}
}
}
};

@ -20,6 +20,10 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
@ -28,10 +32,15 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.annotations.NonNull;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.databinding.ActivitySearchBookBinding;
import xyz.fycz.myreader.entity.SearchBookBean;
@ -49,6 +58,8 @@ import xyz.fycz.myreader.ui.dialog.MultiChoiceDialog;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.webapi.BaseApi;
import xyz.fycz.myreader.webapi.CommonApi;
import xyz.fycz.myreader.webapi.callback.ResultCallback;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -92,6 +103,8 @@ public class SearchBookActivity extends BaseActivity {
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主"};
private static String[] suggestion2 = {"不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
private boolean showHot;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
@ -132,8 +145,7 @@ public class SearchBookActivity extends BaseActivity {
super.initData(savedInstanceState);
mSetting = SysManager.getSetting();
mSearchHistoryService = SearchHistoryService.getInstance();
Collections.addAll(mSuggestions, suggestion);
showHot = !MyApplication.isApkInDebug(this);
searchEngine = new SearchEngine();
searchEngine.setOnSearchListener(new SearchEngine.OnSearchListener() {
@Override
@ -163,9 +175,11 @@ public class SearchBookActivity extends BaseActivity {
});
}
@Override
protected void initWidget() {
super.initWidget();
initSuggestionList();
binding.etSearchKey.requestFocus();//get the focus
//enter事件
binding.etSearchKey.setOnEditorActionListener((textView, i, keyEvent) -> {
@ -238,7 +252,6 @@ public class SearchBookActivity extends BaseActivity {
stopSearch();
mHandler.sendMessage(mHandler.obtainMessage(1));
});
initSuggestionBook();
initHistoryList();
}
@ -247,9 +260,7 @@ public class SearchBookActivity extends BaseActivity {
super.initClick();
//换一批点击事件
binding.renewImage.setOnClickListener(new RenewSuggestionBook());
//换一批点击事件
binding.renewText.setOnClickListener(new RenewSuggestionBook());
binding.llRefreshSuggestBooks.setOnClickListener(new RenewSuggestionBook());
//搜索按钮点击事件
binding.tvSearchConform.setOnClickListener(view -> mHandler.sendMessage(mHandler.obtainMessage(1)));
@ -291,10 +302,19 @@ public class SearchBookActivity extends BaseActivity {
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (!showHot) menu.findItem(R.id.action_hot).setVisible(true);
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_disable_source) {
showDisableSourceDia();
}else if (item.getItemId() == R.id.action_hot){
showHot = !showHot;
initSuggestionList();
}
return super.onOptionsItemSelected(item);
}
@ -348,18 +368,68 @@ public class SearchBookActivity extends BaseActivity {
/**
* 初始化建议书目
*/
private void initSuggestionBook() {
binding.tgSuggestBook.setTags(suggestion);
private void initSuggestionList() {
if (!showHot){
binding.tgSuggestBook.setTags(suggestion);
}else {
SharedPreUtils spu = SharedPreUtils.getInstance();
String cookie = spu.getString(getString(R.string.qdCookie), "");
String url = "https://m.qidian.com/majax/search/auto?kw=&";
if (cookie.equals("")) {
url += "_csrfToken=eXRDlZxmRDLvFAmdgzqvwWAASrxxp2WkVlH4ZM7e";
} else {
url += cookie.split(";")[0];
}
BaseApi.getCommonReturnHtmlStringApi(url, null, "utf-8", true, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
parseSuggestionList((String) o);
if (mSuggestions.size() > 0) {
MyApplication.runOnUiThread(() -> binding.tgSuggestBook.setTags(mSuggestions.subList(0, 5)));
} else {
MyApplication.runOnUiThread(() -> binding.llSuggestBooksView.setVisibility(View.GONE));
}
}
@Override
public void onError(Exception e) {
MyApplication.runOnUiThread(() -> binding.llSuggestBooksView.setVisibility(View.GONE));
}
});
}
}
private void parseSuggestionList(String jsonStr) {
try {
JSONObject json = new JSONObject(jsonStr);
JSONArray names = json.getJSONObject("data").getJSONArray("popWords");
for (int i = 0; i < names.length(); i++) {
mSuggestions.add(names.getJSONObject(i).getString("name"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private class RenewSuggestionBook implements View.OnClickListener {
@Override
public void onClick(View v) {
String[] s = binding.tgSuggestBook.getTags();
if (Arrays.equals(s, suggestion)) {
binding.tgSuggestBook.setTags(suggestion2);
} else {
binding.tgSuggestBook.setTags(suggestion);
if (!showHot) {
String[] s = binding.tgSuggestBook.getTags();
if (Arrays.equals(s, suggestion)) {
binding.tgSuggestBook.setTags(suggestion2);
} else {
binding.tgSuggestBook.setTags(suggestion);
}
}else {
if (mSuggestions.size() > 0) {
String[] s = binding.tgSuggestBook.getTags();
if (s[0].equals(mSuggestions.get(0))) {
binding.tgSuggestBook.setTags(mSuggestions.subList(5, 10));
} else {
binding.tgSuggestBook.setTags(mSuggestions.subList(0, 5));
}
}
}
}
}
@ -407,7 +477,7 @@ public class SearchBookActivity extends BaseActivity {
/*for (ReadCrawler readCrawler : readCrawlers) {
searchBookByCrawler(readCrawler, readCrawler.getSearchCharset());
}*/
searchEngine.initSearchEngine(ReadCrawlerUtil.getReadCrawlers());
searchEngine.initSearchEngine(readCrawlers);
searchEngine.search(searchKey);
}

@ -34,7 +34,7 @@ public class CommonApi extends BaseApi {
* @param url
* @param callback
*/
public static void getBookChapters(String url, final ReadCrawler rc, boolean isRefresh, final ResultCallback callback) {
public static void getBookChapters(String url, final ReadCrawler rc, boolean isRefresh, final ResultCallback callback) {
String charset = rc.getCharset();
getCommonReturnHtmlStringApi(url, null, charset, isRefresh, new ResultCallback() {
@Override
@ -50,7 +50,6 @@ public class CommonApi extends BaseApi {
}
/**
* 获取章节列表
*
@ -94,14 +93,7 @@ public class CommonApi extends BaseApi {
getCommonReturnHtmlStringApi(url, null, charset, true, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
String html = (String) o;
String content = rc.getContentFormHtml(html);
if (rc instanceof YanQingLouReadCrawler && content.contains("正在加载")){
YanQingLouReadCrawler yrc = (YanQingLouReadCrawler) rc;
yrc.getAjaxContent(html, this);
}else {
callback.onFinish(content, 0);
}
callback.onFinish(rc.getContentFormHtml((String) o), 0);
}
@Override
@ -173,7 +165,7 @@ public class CommonApi extends BaseApi {
String finalCharset = charset;
return Observable.create(emitter -> {
try {
if (rc.isPost()){
if (rc.isPost()) {
String url = rc.getSearchLink();
String[] urlInfo = url.split(",");
url = urlInfo[0];
@ -181,7 +173,7 @@ public class CommonApi extends BaseApi {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody requestBody = RequestBody.create(mediaType, body);
emitter.onNext(rc.getBooksFromSearchHtml(OkHttpUtils.getHtml(url, requestBody, finalCharset)));
}else {
} else {
emitter.onNext(rc.getBooksFromSearchHtml(OkHttpUtils.getHtml(makeSearchUrl(rc.getSearchLink(), key), finalCharset)));
}
} catch (Exception e) {
@ -192,7 +184,7 @@ public class CommonApi extends BaseApi {
});
}
public static String makeSearchUrl(String url, String key){
public static String makeSearchUrl(String url, String key) {
return url.replace("{key}", key);
}
@ -203,9 +195,9 @@ public class CommonApi extends BaseApi {
*/
public static Observable<Book> getBookInfo(final Book book, final BookInfoCrawler bic) {
String url;
if (StringHelper.isEmpty(book.getInfoUrl())){
if (StringHelper.isEmpty(book.getInfoUrl())) {
url = book.getChapterUrl();
}else {
} else {
url = book.getInfoUrl();
}
return Observable.create(emitter -> {
@ -227,7 +219,7 @@ public class CommonApi extends BaseApi {
*/
public static void getBookInfo(final Book book, final BookInfoCrawler bic, final ResultCallback callback) {
String url = book.getInfoUrl();
if (StringHelper.isEmpty(url)){
if (StringHelper.isEmpty(url)) {
url = book.getChapterUrl();
}
getCommonReturnHtmlStringApi(url, null, bic.getCharset(), false, new ResultCallback() {
@ -256,6 +248,7 @@ public class CommonApi extends BaseApi {
public void onFinish(final Object o, int code) {
LanZousApi.getKey((String) o, new ResultCallback() {
final String referer = (String) o;
@Override
public void onFinish(Object o, int code) {
LanZousApi.getUrl2((String) o, new ResultCallback() {

@ -86,15 +86,11 @@ public class Ben100ReadCrawler extends FindCrawler implements ReadCrawler, BookI
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -199,7 +195,7 @@ public class Ben100ReadCrawler extends FindCrawler implements ReadCrawler, BookI
bookType.setTypeName(name);
bookType.setUrl(url);
bookTypes.add(bookType);
System.out.println("bookTypes.put(\""+ bookType.getTypeName() + "\", \"" + bookType.getUrl() + "\");");
System.out.println("bookTypes.put(\"" + bookType.getTypeName() + "\", \"" + bookType.getUrl() + "\");");
}
return bookTypes;
}
@ -208,7 +204,7 @@ public class Ben100ReadCrawler extends FindCrawler implements ReadCrawler, BookI
public List<BookType> getBookTypes() {
initBookTypes();
List<BookType> bookTypes = new ArrayList<>();
for (String name : mBookTypes.keySet()){
for (String name : mBookTypes.keySet()) {
BookType bookType = new BookType();
bookType.setTypeName(name);
bookType.setUrl(mBookTypes.get(name));
@ -217,7 +213,7 @@ public class Ben100ReadCrawler extends FindCrawler implements ReadCrawler, BookI
return bookTypes;
}
private void initBookTypes(){
private void initBookTypes() {
mBookTypes.put("世界名著", "https://www.100ben.net/shijiemingzhu/");
mBookTypes.put("现代文学", "https://www.100ben.net/xiandaiwenxue/");
mBookTypes.put("外国小说", "https://www.100ben.net/waiguoxiaoshuo/");
@ -245,7 +241,8 @@ public class Ben100ReadCrawler extends FindCrawler implements ReadCrawler, BookI
String page = pageDiv.getElementsByTag("a").last().text();
String pageStr = page.replace("末页(", "").replace(")", "");
bookType.setPageSize(Integer.parseInt(pageStr));
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
Elements divs = doc.getElementsByClass("recommand");
Element div = divs.get(0);

@ -58,15 +58,11 @@ public class BiJianReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementsByClass("read-content").first();
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -95,13 +91,13 @@ public class BiJianReadCrawler implements ReadCrawler {
/**
* 从搜索html中得到书列表
*<li>
* <a class="pic" href="http://www.bjcan.com/book/74544.html" target="_blank"><img class="lazy" src="http://www.bjcan.com/uploads/novel/20200907/b38cea14e4a3de1e876395e378c1e544.jpeg" alt="大主宰:灵玖"></a>
* <h5 class="tit"><a href="http://www.bjcan.com/book/74544.html" target="_blank">大主宰灵玖</a></h5>
* <p class="info">作者<span>霞露</span><span>分类其他</span><i class="serial">连载中</i></p>
* <p class="intro">简介身负系统莫名来到了大主宰的时空成为了聚灵族的最后族人在她还对周围的情况一片模糊的时候她遇到了林静这个小恶魔拜林静所赐她还遇到了武祖成为了武柤的小徒弟参与了灵路遇到了牧尘和洛璃她默默的在心中问着自己那一直在划水的系统&ldquo;你的活来了说吧我该干什么&rdquo;</p>
* <a class="view" href="http://www.bjcan.com/book/74544.html" target="_blank">小说详情</a>
*</li>
* <li>
* <a class="pic" href="http://www.bjcan.com/book/74544.html" target="_blank"><img class="lazy" src="http://www.bjcan.com/uploads/novel/20200907/b38cea14e4a3de1e876395e378c1e544.jpeg" alt="大主宰:灵玖"></a>
* <h5 class="tit"><a href="http://www.bjcan.com/book/74544.html" target="_blank">大主宰灵玖</a></h5>
* <p class="info">作者<span>霞露</span><span>分类其他</span><i class="serial">连载中</i></p>
* <p class="intro">简介身负系统莫名来到了大主宰的时空成为了聚灵族的最后族人在她还对周围的情况一片模糊的时候她遇到了林静这个小恶魔拜林静所赐她还遇到了武祖成为了武柤的小徒弟参与了灵路遇到了牧尘和洛璃她默默的在心中问着自己那一直在划水的系统&ldquo;你的活来了说吧我该干什么&rdquo;</p>
* <a class="view" href="http://www.bjcan.com/book/74544.html" target="_blank">小说详情</a>
* </li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -18,10 +20,12 @@ import java.util.ArrayList;
public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NAME_SPACE = "https://www.wqge.cc";
public static final String NOVEL_SEARCH = "https://www.wqge.cc/modules/article/search.php?searchkey={key}";
public static final String NAME_SPACE = "http://www.wqge.net";
// public static final String NAME_SPACE = "https://www.wqge.cc";
public static final String NOVEL_SEARCH = "http://www.wqge.net/modules/article/search.php?searchkey={key}";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
@ -36,10 +40,12 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
@ -47,21 +53,18 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -83,7 +86,7 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler {
Elements as = dd.getElementsByTag("a");
if (as.size() > 0) {
Element a = as.get(0);
String title = a.text() ;
String title = a.text();
if (!StringHelper.isEmpty(lastTile) && title.equals(lastTile)) {
continue;
}
@ -101,6 +104,7 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
@ -127,9 +131,10 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book){
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
Element img = doc.getElementById("fmimg");
book.setImgUrl(img.getElementsByTag("img").get(0).attr("src"));

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -55,15 +57,11 @@ public class CansShu99ReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -107,28 +105,28 @@ public class CansShu99ReadCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Elements divs = doc.getElementsByClass("list_box");
Element div = divs.get(0);
Elements elementsByTag = div.getElementsByTag("li");
for (Element element : elementsByTag) {
Book book = new Book();
String name = element.getElementsByTag("h2").first().getElementsByTag("a").first().text();
book.setName(name);
String author = element.getElementsByTag("h4").first().getElementsByTag("a").first().text();
book.setAuthor(author);
String type = element.getElementsByTag("h4").get(1).getElementsByTag("a").text();
book.setType(type);
String desc = element.getElementsByClass("intro").first().text();
book.setDesc(desc);
String imgUrl = element.getElementsByTag("img").first().attr("src");
book.setImgUrl("http:" + imgUrl);
String chapterUrl = element.getElementsByTag("h2").first().getElementsByTag("a").first().attr("href");
book.setChapterUrl(NAME_SPACE + chapterUrl);
book.setNewestChapterTitle("");
book.setSource(BookSource.cangshu99.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Elements divs = doc.getElementsByClass("list_box");
Element div = divs.get(0);
Elements elementsByTag = div.getElementsByTag("li");
for (Element element : elementsByTag) {
Book book = new Book();
String name = element.getElementsByTag("h2").first().getElementsByTag("a").first().text();
book.setName(name);
String author = element.getElementsByTag("h4").first().getElementsByTag("a").first().text();
book.setAuthor(author);
String type = element.getElementsByTag("h4").get(1).getElementsByTag("a").text();
book.setType(type);
String desc = element.getElementsByClass("intro").first().text();
book.setDesc(desc);
String imgUrl = element.getElementsByTag("img").first().attr("src");
book.setImgUrl("http:" + imgUrl);
String chapterUrl = element.getElementsByTag("h2").first().getElementsByTag("a").first().attr("href");
book.setChapterUrl(NAME_SPACE + chapterUrl);
book.setNewestChapterTitle("");
book.setSource(BookSource.cangshu99.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }

@ -58,25 +58,21 @@ public class ChuanQiReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**

@ -57,15 +57,11 @@ public class DSTQReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -105,7 +101,7 @@ public class DSTQReadCrawler implements ReadCrawler {
try {
Element div = doc.getElementsByClass("library").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis){
for (Element li : lis) {
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());

@ -27,6 +27,7 @@ public class Du1DuReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NOVEL_SEARCH = "http://du1du.org/search.htm?keyword={key}";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
@ -41,10 +42,12 @@ public class Du1DuReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
@ -52,26 +55,23 @@ public class Du1DuReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txtContent");
if (divContent != null) {
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()){
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()) {
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -101,6 +101,7 @@ public class Du1DuReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
@ -130,9 +131,10 @@ public class Du1DuReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book){
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
Element img = doc.selectFirst("meta[property=og:image]");
book.setImgUrl(img.attr("content"));

@ -0,0 +1,151 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class EWenXueReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NAME_SPACE = "http://ewenxue.org";
public static final String NOVEL_SEARCH = "http://ewenxue.org/search.htm?keyword={key}";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("cContent");
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("setFontSize();", "");
return content;
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = NAME_SPACE + doc.select(".breadcrumb").first()
.select("a").last().attr("href");
Element divList = doc.getElementById("chapters-list");
String lastTile = null;
int i = 0;
Elements elementsByTag = divList.getElementsByTag("a");
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
if (!StringHelper.isEmpty(lastTile) && title.equals(lastTile)) {
continue;
}
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
String url = readUrl + a.attr("href");
chapter.setUrl(url);
chapters.add(chapter);
lastTile = title;
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <li class="list-group-item clearfix">
* <div class="col-xs-1"><i class="tag-blue">玄幻</i></div>
* <div class="col-xs-3"><a href="/xs/163283/">大主宰</a></div>
* <div class="col-xs-4"><a href="/xs/163283/56818254.htm">第一千三十二章 七阳截天杖</a></div>
* <div class="col-xs-2">天蚕土豆</div>
* <div class="col-xs-2"><span class="time">2019-07-05 16:03</span></div>
* </li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
Elements elements = doc.getElementsByClass("clearfix");
for (int i = 1; i < elements.size(); i++) {
Element element = elements.get(i);
Book book = new Book();
Elements info = element.getElementsByTag("div");
book.setName(info.get(1).text());
book.setInfoUrl(NAME_SPACE + info.get(1).getElementsByTag("a").attr("href"));
book.setChapterUrl(book.getInfoUrl() + "mulu.htm");
book.setAuthor(info.get(3).text());
book.setNewestChapterTitle(info.get(2).text());
book.setType(info.get(0).text());
book.setSource(BookSource.ewenxue.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
return books;
}
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
Element img = doc.getElementsByClass("img-thumbnail").first();
book.setImgUrl(img.attr("src"));
Element desc = doc.getElementById("all");
if (desc == null) {
desc = doc.getElementById("shot");
}
book.setDesc(desc.text().replace("[收起]", ""));
return book;
}
}

@ -58,25 +58,21 @@ public class HongChenReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -130,24 +126,24 @@ public class HongChenReadCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("s-b-list").first();
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls){
Elements as = dl.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最近更新 ", ""));
book.setDesc(dl.getElementsByClass("big-book-info").first().text());
String imgUrl = dl.getElementsByTag("img").attr("data-original");
book.setImgUrl(imgUrl);
//https://www.zuxs.net/zu/1140.html -> https://www.zuxs.net/zu/1/1140/
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("zu/", "zu/1/").replace(".html", "/"));
book.setSource(BookSource.hongchen.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Element div = doc.getElementsByClass("s-b-list").first();
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls) {
Elements as = dl.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最近更新 ", ""));
book.setDesc(dl.getElementsByClass("big-book-info").first().text());
String imgUrl = dl.getElementsByTag("img").attr("data-original");
book.setImgUrl(imgUrl);
//https://www.zuxs.net/zu/1140.html -> https://www.zuxs.net/zu/1/1140/
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("zu/", "zu/1/").replace(".html", "/"));
book.setSource(BookSource.hongchen.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -55,15 +57,11 @@ public class JiuTaoReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("您可以在.*最新章节!|\\\\", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("您可以在.*最新章节!|\\\\", "");
return content;
}
/**
@ -101,22 +99,22 @@ public class JiuTaoReadCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("library").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis){
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最新章节:", ""));
book.setDesc(li.getElementsByClass("intro").first().text());
book.setImgUrl(li.getElementsByTag("img").attr("src"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace(".html", "/"));
book.setSource(BookSource.jiutao.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Element div = doc.getElementsByClass("library").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis) {
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("最新章节:", ""));
book.setDesc(li.getElementsByClass("intro").first().text());
book.setImgUrl(li.getElementsByTag("img").attr("src"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace(".html", "/"));
book.setSource(BookSource.jiutao.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }

@ -61,25 +61,21 @@ public class LaoYaoReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**

@ -26,8 +26,8 @@ import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
*/
public class LiuLangCatReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "http://m.liulangcat.com";
public static final String NOVEL_SEARCH = "http://m.liulangcat.com/get/get_search_result.php?page=0&keyword={key}";
// public static final String NOVEL_SEARCH = "http://www.liulangcat.com/search.php?k={key}&submit=搜索&wgxojg=wc0yz&uwzgzw=yi1p7&amlmvy=mcp50&rybwbm=1s0y7";
public static final String NOVEL_SEARCH = "http://m.liulangcat.com/get/get_search_result.php?page=0&keyword={key}";
// public static final String NOVEL_SEARCH = "http://www.liulangcat.com/search.php?k={key}&submit=搜索&wgxojg=wc0yz&uwzgzw=yi1p7&amlmvy=mcp50&rybwbm=1s0y7";
public static final String CHARSET = "utf-8";
public static final String SEARCH_CHARSET = "utf-8";
@ -154,17 +154,13 @@ public class LiuLangCatReadCrawler implements ReadCrawler {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementsByClass("item_content").first();
Element nameSpan = doc.getElementsByClass("top_categoryname").first();
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").
replace(nameSpan.text(), "").
replace("主页", "").
replace("目录", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").
replace(nameSpan.text(), "").
replace("主页", "").
replace("目录", "");
return content;
}
}

@ -0,0 +1,172 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class LuoQiuReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NAME_SPACE = "https://www.lqbook.com";
public static final String NOVEL_SEARCH = "https://www.lqbook.com/modules/article/search.php?searchkey={key}&submit=%CB%D1%CB%F7";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "GBK";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ")
.replaceAll("^.*最新章节!", "");
return content;
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.selectFirst(".zjlist");
String lastTile = null;
int i = 0;
Elements elementsByTag = divList.getElementsByTag("a");
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
if (!StringHelper.isEmpty(lastTile) && title.equals(lastTile)) {
continue;
}
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
String url = readUrl + a.attr("href");
chapter.setUrl(url);
chapters.add(chapter);
lastTile = title;
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <tr>
* <td class="odd" align="center"><a href="https://www.lqbook.com/book_91153/">文娱大主宰</a></td>
* <td class="even" align="center"><a href="https://www.lqbook.com/book_91153/52814257.html" target="_blank" title=" 很抱歉,是时候结束了。">很抱歉是时候结束了</a></td>
* <td class="odd" align="center">羽林都督</td>
* <td class="even" align="center">480K</td>
* <td class="odd" align="center">20-10-02</td>
* <td class="even" align="center">连载</td>
* </tr>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(html, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Element div = doc.getElementById("main");
Elements elements = div.getElementsByTag("tr");
for (int i = 1; i < elements.size(); i++) {
Element element = elements.get(i);
Book book = new Book();
Elements info = element.getElementsByTag("td");
book.setName(info.get(0).text());
book.setChapterUrl(info.get(0).selectFirst("a").attr("href"));
book.setAuthor(info.get(2).text());
book.setNewestChapterTitle(info.get(1).text());
book.setSource(BookSource.luoqiu.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
return books;
}
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
book.setSource(BookSource.luoqiu.toString());
String name = doc.select("meta[property=og:title]").attr("content");
book.setName(name);
String url = doc.select("meta[property=og:novel:read_url]").attr("content");
book.setChapterUrl(url);
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
String newestChapter = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapter);
Element img = doc.getElementById("picbox");
book.setImgUrl(img.getElementsByTag("img").get(0).attr("src"));
Element desc = doc.getElementById("intro");
book.setDesc(Html.fromHtml(desc.html()).toString());
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
return book;
}
}

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -56,15 +58,11 @@ public class MiQuReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("applyChapterSetting();", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("applyChapterSetting();", "");
return content;
}
/**

@ -83,15 +83,11 @@ public class MiaoBiReadCrawler extends FindCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("您可以在.*最新章节!|\\\\", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("您可以在.*最新章节!|\\\\", "");
return content;
}
/**
@ -129,22 +125,22 @@ public class MiaoBiReadCrawler extends FindCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementById("sitembox");
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls){
Elements as = dl.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(3).text());
book.setType(as.get(2).text());
book.setNewestChapterTitle(as.get(4).text());
book.setDesc(dl.getElementsByClass("book_des").first().text());
book.setImgUrl(as.first().getElementsByTag("img").attr("src"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("novel", "read").replace(".html", "/"));
book.setSource(BookSource.miaobi.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Element div = doc.getElementById("sitembox");
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls) {
Elements as = dl.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(3).text());
book.setType(as.get(2).text());
book.setNewestChapterTitle(as.get(4).text());
book.setDesc(dl.getElementsByClass("book_des").first().text());
book.setImgUrl(as.first().getElementsByTag("img").attr("src"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("novel", "read").replace(".html", "/"));
book.setSource(BookSource.miaobi.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }
@ -155,7 +151,7 @@ public class MiaoBiReadCrawler extends FindCrawler implements ReadCrawler {
public List<BookType> getBookTypes() {
initBookTypes();
List<BookType> bookTypes = new ArrayList<>();
for (String name : mBookTypes.keySet()){
for (String name : mBookTypes.keySet()) {
BookType bookType = new BookType();
bookType.setTypeName(name);
bookType.setUrl(mBookTypes.get(name));
@ -165,7 +161,7 @@ public class MiaoBiReadCrawler extends FindCrawler implements ReadCrawler {
return bookTypes;
}
private void initBookTypes(){
private void initBookTypes() {
mBookTypes.put("玄幻奇幻", "https://www.imiaobige.com/xuanhuan/1.html");
mBookTypes.put("武侠仙侠", "https://www.imiaobige.com/wuxia/1.html");
mBookTypes.put("都市生活", "https://www.imiaobige.com/dushi/1.html");
@ -189,7 +185,7 @@ public class MiaoBiReadCrawler extends FindCrawler implements ReadCrawler {
Document doc = Jsoup.parse(html);
Element div = doc.getElementById("sitebox");
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls){
for (Element dl : dls) {
Book book = new Book();
Elements as = dl.getElementsByTag("a");
book.setName(as.get(1).text());
@ -208,7 +204,7 @@ public class MiaoBiReadCrawler extends FindCrawler implements ReadCrawler {
@Override
public boolean getTypePage(BookType curType, int page) {
if (page > curType.getPageSize()){
if (page > curType.getPageSize()) {
return true;
}
curType.setUrl(curType.getUrl().substring(0, curType.getUrl().lastIndexOf("/") + 1) + page + ".html");

@ -23,6 +23,7 @@ public class PiaoTianReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NOVEL_SEARCH = "https://www.piaotian.org/modules/article/search.php?searchkey={key}&submit=%CB%D1%CB%F7";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "GBK";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
@ -37,10 +38,12 @@ public class PiaoTianReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
@ -48,21 +51,18 @@ public class PiaoTianReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("htmlContent");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("飘天文学.*最新章节!", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("飘天文学.*最新章节!", "");
return content;
}
/**
@ -93,6 +93,7 @@ public class PiaoTianReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
@ -132,9 +133,10 @@ public class PiaoTianReadCrawler implements ReadCrawler, BookInfoCrawler {
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book){
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
Element name = doc.selectFirst("meta[property=og:novel:book_name]");
book.setName(name.attr("content"));

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -42,14 +44,17 @@ public class PinShuReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
@ -59,16 +64,12 @@ public class PinShuReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("BookText");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("品书网", "")
.replace("手机阅读", "");
return StringHelper.IgnoreCaseReplace(content, "www.vodtw.com", "");
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("品书网", "")
.replace("手机阅读", "");
return StringHelper.IgnoreCaseReplace(content, "www.vodtw.com", "");
}
/**

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -41,10 +43,12 @@ public class PinShuReadCrawler2 implements ReadCrawler, BookInfoCrawler {
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
@ -59,16 +63,12 @@ public class PinShuReadCrawler2 implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("BookText");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("品书网", "")
.replace("手机阅读", "");
return StringHelper.IgnoreCaseReplace(content, "www.vodtw.com", "");
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("品书网", "")
.replace("手机阅读", "");
return StringHelper.IgnoreCaseReplace(content, "www.vodtw.com", "");
}
/**

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.enums.BookSource;
@ -37,10 +39,12 @@ public class QB5ReadCrawler extends FindCrawler implements ReadCrawler, BookInfo
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getCharset() {
return CHARSET;
@ -89,7 +93,8 @@ public class QB5ReadCrawler extends FindCrawler implements ReadCrawler, BookInfo
BookType bookType = new BookType();
bookType.setTypeName(a.attr("title"));
bookType.setUrl(a.attr("href"));
if (bookType.getTypeName().contains("首页") || bookType.getTypeName().contains("热门小说")) continue;
if (bookType.getTypeName().contains("首页") || bookType.getTypeName().contains("热门小说"))
continue;
if (!StringHelper.isEmpty(bookType.getTypeName())) {
bookTypes.add(bookType);
}
@ -138,7 +143,8 @@ public class QB5ReadCrawler extends FindCrawler implements ReadCrawler, BookInfo
try {
int pageSize = Integer.parseInt(doc.getElementsByClass("last").first().text());
bookType.setPageSize(pageSize);
}catch (Exception ignored){}
} catch (Exception ignored) {
}
String type = doc.select("meta[name=keywords]").attr("content").replace(",全本小说网", "");
Element div = doc.getElementById("tlist");
Elements uls = div.getElementsByTag("ul");
@ -170,16 +176,12 @@ public class QB5ReadCrawler extends FindCrawler implements ReadCrawler, BookInfo
Element divBook = doc.getElementsByClass("nav-style").get(0);
String bookName = divBook.getElementsByTag("a").get(1).attr("title");
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
content = content.replaceAll("全本小说.*最新章节!", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
content = content.replaceAll("全本小说.*最新章节!", "");
return content;
}
@ -276,16 +278,16 @@ public class QB5ReadCrawler extends FindCrawler implements ReadCrawler, BookInfo
}
public boolean getTypePage(BookType curType, int page){
if (curType.getPageSize() <= 0){
public boolean getTypePage(BookType curType, int page) {
if (curType.getPageSize() <= 0) {
curType.setPageSize(10);
}
if (page > curType.getPageSize()){
if (page > curType.getPageSize()) {
return true;
}
if (!curType.getTypeName().equals("完本小说")) {
curType.setUrl(curType.getUrl().substring(0, curType.getUrl().lastIndexOf("_") + 1) + page + "/");
}else {
} else {
curType.setUrl(curType.getUrl().substring(0, curType.getUrl().lastIndexOf("/") + 1) + page);
}
return false;

@ -5,6 +5,7 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -59,20 +60,16 @@ public class QiQiReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()){
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("奇奇小说全网.*com|更新最.*com\\\\/|哽噺.*com|www.*com\"", "");
return content;
} else {
return "";
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()) {
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("奇奇小说全网.*com|更新最.*com\\\\/|哽噺.*com|www.*com\"", "");
return content;
}
/**

@ -1,11 +1,13 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -57,20 +59,16 @@ public class QuanNovelReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()){
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("\\s*您可以.*最.*章节.*", "");
return content;
} else {
return "";
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()) {
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("\\s*您可以.*最.*章节.*", "");
return content;
}
/**

@ -61,25 +61,21 @@ public class ReXueReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**

@ -58,25 +58,21 @@ public class ShiGuangReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**

@ -0,0 +1,178 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class ShuHaiGeReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NAME_SPACE = "https://www.xinshuhaige.net";
public static final String NOVEL_SEARCH = "https://www.xinshuhaige.net/search.html,searchkey={key}&searchtype=all";
public static final String CHARSET = "utf-8";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return true;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementsByClass("content").first();
StringBuilder sb = new StringBuilder();
List<TextNode> textNodes = divContent.textNodes();
for (int i = 1; i < textNodes.size() - 6; i++) {
TextNode textNode = textNodes.get(i);
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
Element divList = doc.getElementsByClass("novel_list").last();
String lastTile = null;
int i = 0;
Elements elementsByTag = divList.getElementsByTag("a");
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
if (!StringHelper.isEmpty(lastTile) && title.equals(lastTile)) {
continue;
}
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
String url = NAME_SPACE + a.attr("href");
chapter.setUrl(url);
chapters.add(chapter);
lastTile = title;
}
try {
Element pages = doc.getElementById("pagelink");
if (pages != null) {
String nextPageUrl = "";
Element nextPage = doc.selectFirst(".caption")
.selectFirst("a");
if ("下一页".equals(nextPage.text())) {
nextPageUrl = NAME_SPACE + nextPage.attr("href");
}
if (!StringHelper.isEmpty(nextPageUrl)) {
List<Chapter> nextChapters = getChaptersFromHtml(OkHttpUtils.getHtml(nextPageUrl, CHARSET));
for (Chapter nextChapter : nextChapters) {
nextChapter.setNumber(chapters.size());
chapters.add(nextChapter);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <li>
* <span class="s1">[<a href="/dushi/">都市生活</a>]</span>
* <span class="s2"><a href="/136610/" target="_blank">都市大主宰</a></span>
* <span class="s3"><a href="/136610/4031638.html" target="_blank">第1462章  相似</a></span>
* <span class="s4">赌霸</span>
* <span class="s5">2021-02-05</span>
* <span class="s6">连载</span>
* </li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
Element div = doc.getElementsByClass("novelslist2").first();
Elements elements = div.getElementsByTag("li");
for (int i = 1; i < elements.size(); i++) {
Element element = elements.get(i);
Book book = new Book();
Elements info = element.getElementsByTag("span");
book.setName(info.get(1).text());
book.setChapterUrl(NAME_SPACE + info.get(1).getElementsByTag("a").attr("href"));
book.setAuthor(info.get(3).text());
book.setNewestChapterTitle(info.get(2).text());
book.setType(info.get(0).getElementsByTag("a").first().text());
book.setSource(BookSource.shuhaige.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
return books;
}
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
String img = doc.select("meta[property=og:image]").attr("content");
book.setImgUrl(img);
String desc = doc.select("meta[property=og:description]").attr("content");
book.setDesc(desc.replaceAll("新书海阁.*观看小说:", ""));
return book;
}
}

@ -1,11 +1,13 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -58,20 +60,16 @@ public class SoNovelReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementsByClass("content").first();
if (divContent != null) {
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()){
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("\\s*您可以.*最.*章节.*", "");
return content;
} else {
return "";
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()) {
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("\\s*您可以.*最.*章节.*", "");
return content;
}
/**

@ -6,6 +6,7 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -21,8 +22,9 @@ import java.util.ArrayList;
*/
public class TianLaiReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.23txt.com";
public static final String NOVEL_SEARCH = "https://www.23txt.com/search.php?q={key}";
// public static final String NAME_SPACE = "https://www.23txt.com";
public static final String NAME_SPACE = "https://www.233txt.com";
public static final String NOVEL_SEARCH = "https://www.233txt.com/search.php?q={key}";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "utf-8";
@ -30,6 +32,7 @@ public class TianLaiReadCrawler implements ReadCrawler {
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
@ -39,10 +42,12 @@ public class TianLaiReadCrawler implements ReadCrawler {
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
@ -57,16 +62,12 @@ public class TianLaiReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
content = content.replaceAll("笔趣阁.*最新章节!", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
content = content.replaceAll("笔趣阁.*最新章节!", "");
return content;
}
/**
@ -83,7 +84,7 @@ public class TianLaiReadCrawler implements ReadCrawler {
Element dl = divList.getElementsByTag("dl").get(0);
String lastTile = null;
int i = 0;
for(Element dd : dl.getElementsByTag("dd")){
for (Element dd : dl.getElementsByTag("dd")) {
Elements as = dd.getElementsByTag("a");
if (as.size() > 0) {
Element a = as.get(0);
@ -97,7 +98,7 @@ public class TianLaiReadCrawler implements ReadCrawler {
String url = a.attr("href");
if (url.contains("files/article/html")) {
url = NAME_SPACE + url;
}else {
} else {
url = readUrl + url;
}
chapter.setUrl(url);

@ -57,15 +57,11 @@ public class WoLongReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("contentsource");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -95,19 +91,19 @@ public class WoLongReadCrawler implements ReadCrawler {
/**
* 从搜索html中得到书列表
<div>
<a href="http://www.paper027.com/novel/75432.html" target="_blank"><img class="img-rounded" src="http://www.paper027.com/uploads/novel/20190802/9883298e2e72ecfa53fabf0ef2e03e21.jpg"/></a>
<h2><a href="http://www.paper027.com/novel/75432.html" target="_blank">大主宰之混子日常</a></h2>
<p class="text-muted"><span>錯過过错</span> <small>2019-08-06 19:14</small></p>
</div>
<div class="clearfix searchresult-info">
<p><a href="http://www.paper027.com/novel/75432.html" target="_blank">作者很懒什么也没有留下...</a></p>
<ul class="list-inline text-muted">
<li>11635人看过</li>
<li>标签</li>
<li><a class="text-warning">同人衍生</a></li>
</ul>
</div>
* <div>
* <a href="http://www.paper027.com/novel/75432.html" target="_blank"><img class="img-rounded" src="http://www.paper027.com/uploads/novel/20190802/9883298e2e72ecfa53fabf0ef2e03e21.jpg"/></a>
* <h2><a href="http://www.paper027.com/novel/75432.html" target="_blank">大主宰之混子日常</a></h2>
* <p class="text-muted"><span>錯過过错</span> <small>2019-08-06 19:14</small></p>
* </div>
* <div class="clearfix searchresult-info">
* <p><a href="http://www.paper027.com/novel/75432.html" target="_blank">作者很懒什么也没有留下...</a></p>
* <ul class="list-inline text-muted">
* <li>11635人看过</li>
* <li>标签</li>
* <li><a class="text-warning">同人衍生</a></li>
* </ul>
* </div>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();

@ -0,0 +1,146 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class XBiQuGeReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.xquge.com";
public static final String NOVEL_SEARCH = "https://www.xquge.com/search?keyword={key}&sign=";
public static final String CHARSET = "UTF-8";
public static final String SEARCH_CHARSET = "UTF-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replace("applyChapterSetting();", "");
return content;
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
Element divList = doc.getElementsByClass("catelog_list").last();
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <li>
* <div class="rank_items">
* <div class="items_l"><a href="https://www.xquge.com/book/5661.html" class="book_img"><img
* src="//static.xquge.com/Public/upload/book/201912/23/22/5715770830115e0060832a553.jpg?v=2020060502"
* alt="绝世元尊"></a></div>
* <div class="items_center">
* <div class="rank_bkname"><a href="https://www.xquge.com/book/5661.html">异界大主宰</a></div>
* <div class="rank_bkinfo"><span class="author">范范的萧</span><span>玄幻奇幻</span><span>连载</span>
* </div>
* <div class="rank_bkbrief">
* 怎么回事 冷尧一脸茫然这是哪儿他看着这个陌生的的环境一时不知所错 冷尧看着自己有一双粗大而又充满爆发力的大手每个细胞都充满爆发力 这具身体不是自己的难道我穿越了 </div>
* <div class="rank_bkother">
* <div class="rank_bktime">2020-08-28 04:24</div>
* <div class="rank_newpage"><a href="https://www.xquge.com/book/5661/98087932.html">更新章节新书苍山牧云记以发布</a>
* </div>
* </div>
* </div>
* <div class="items_rig">
* <a href="https://www.xquge.com/book/5661.html" class="bk_brief_btn">书籍详情</a></div>
* </div>
* </li>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("rank_ullist");
Element div = divs.get(0);
Elements elementsByTag = div.getElementsByTag("li");
for (int i = 0; i < elementsByTag.size(); i++) {
Element element = elementsByTag.get(i);
Book book = new Book();
Elements as = element.getElementsByTag("a");
book.setName(as.get(1).text());
book.setChapterUrl(as.get(1).attr("href"));
book.setNewestChapterTitle(as.get(2).text().replace("更新章节:", ""));
String img = as.first().selectFirst("img").attr("src");
if (!img.contains("http")) img = "https:" + img;
book.setImgUrl(img);
Elements spans = element.selectFirst(".rank_bkinfo").select("span");
book.setAuthor(spans.first().text());
book.setType(spans.get(1).text());
book.setDesc(element.selectFirst(".rank_bkbrief").text());
book.setSource(BookSource.xbiquge.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
return books;
}
}

@ -81,15 +81,11 @@ public class XS7ReadCrawler extends FindCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("一秒记住.*免费阅读!", "");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("一秒记住.*免费阅读!", "");
return content;
}
/**
@ -128,21 +124,21 @@ public class XS7ReadCrawler extends FindCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element alist = doc.getElementById("alist");
Elements divs = alist.select("#alistbox");
for (Element div : divs){
Elements as = div.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(div.getElementsByTag("span").first().text().replace("作者:", ""));
book.setNewestChapterTitle(as.get(2).text());
book.setDesc(div.getElementsByClass("intro").first().text());
book.setImgUrl(div.getElementsByTag("img").attr("src"));
book.setChapterUrl(as.get(1).attr("href"));
book.setSource(BookSource.xs7.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Element alist = doc.getElementById("alist");
Elements divs = alist.select("#alistbox");
for (Element div : divs) {
Elements as = div.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(div.getElementsByTag("span").first().text().replace("作者:", ""));
book.setNewestChapterTitle(as.get(2).text());
book.setDesc(div.getElementsByClass("intro").first().text());
book.setImgUrl(div.getElementsByTag("img").attr("src"));
book.setChapterUrl(as.get(1).attr("href"));
book.setSource(BookSource.xs7.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }
@ -155,7 +151,7 @@ public class XS7ReadCrawler extends FindCrawler implements ReadCrawler {
Document doc = Jsoup.parse(html);
Element div = doc.getElementsByClass("subnav-hot").first();
Elements as = div.getElementsByTag("a");
for (Element a : as){
for (Element a : as) {
BookType bookType = new BookType();
bookType.setUrl(a.attr("href"));
bookType.setTypeName(a.text());
@ -192,7 +188,7 @@ public class XS7ReadCrawler extends FindCrawler implements ReadCrawler {
bookType.setPageSize(Integer.parseInt(last.text()));
Element div = doc.getElementById("alist");
Elements bDivs = div.select("div[id=alistbox]");
for (Element bDiv : bDivs){
for (Element bDiv : bDivs) {
Book book = new Book();
Element title = bDiv.getElementsByClass("title").first();
Element sys = bDiv.getElementsByClass("sys").first();
@ -212,7 +208,7 @@ public class XS7ReadCrawler extends FindCrawler implements ReadCrawler {
@Override
public boolean getTypePage(BookType curType, int page) {
if (page != 1 && page > curType.getPageSize()){
if (page != 1 && page > curType.getPageSize()) {
return true;
}
curType.setUrl(curType.getUrl().substring(0, curType.getUrl().lastIndexOf("_") + 1) + page + ".html");

@ -0,0 +1,172 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class XS7ReadCrawler2 implements ReadCrawler, BookInfoCrawler {
public static final String NAME_SPACE = "https://www.xs7.co";
public static final String NOVEL_SEARCH = "https://www.xs7.co/modules/article/search.php?searchkey={key}&submit=%CB%D1%CB%F7";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "GBK";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ")
.replaceAll("^.*最新章节!", "");
return content;
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.selectFirst(".zjlist");
String lastTile = null;
int i = 0;
Elements elementsByTag = divList.getElementsByTag("a");
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
if (!StringHelper.isEmpty(lastTile) && title.equals(lastTile)) {
continue;
}
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
String url = readUrl + a.attr("href");
chapter.setUrl(url);
chapters.add(chapter);
lastTile = title;
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <tr>
* <td class="odd" align="center"><a href="https://www.lqbook.com/book_91153/">文娱大主宰</a></td>
* <td class="even" align="center"><a href="https://www.lqbook.com/book_91153/52814257.html" target="_blank" title=" 很抱歉,是时候结束了。">很抱歉是时候结束了</a></td>
* <td class="odd" align="center">羽林都督</td>
* <td class="even" align="center">480K</td>
* <td class="odd" align="center">20-10-02</td>
* <td class="even" align="center">连载</td>
* </tr>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(html, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Element div = doc.getElementById("main");
Elements elements = div.getElementsByTag("tr");
for (int i = 1; i < elements.size(); i++) {
Element element = elements.get(i);
Book book = new Book();
Elements info = element.getElementsByTag("td");
book.setName(info.get(0).text());
book.setChapterUrl(info.get(0).selectFirst("a").attr("href"));
book.setAuthor(info.get(2).text());
book.setNewestChapterTitle(info.get(1).text());
book.setSource(BookSource.xs7.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
return books;
}
/**
* 获取书籍详细信息
*
* @param book
*/
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
book.setSource(BookSource.xs7.toString());
String name = doc.select("meta[property=og:title]").attr("content");
book.setName(name);
String url = doc.select("meta[property=og:novel:read_url]").attr("content");
book.setChapterUrl(url);
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
String newestChapter = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapter);
Element img = doc.getElementById("picbox");
book.setImgUrl(img.getElementsByTag("img").get(0).attr("src"));
Element desc = doc.getElementById("intro");
book.setDesc(Html.fromHtml(desc.html()).toString());
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
return book;
}
}

@ -58,25 +58,21 @@ public class XiaGuReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
Elements aDiv = divContent.getElementsByTag("dd");
StringBuilder sb = new StringBuilder();
Collections.sort(aDiv, (o1, o2) -> Integer.parseInt(o1.attr("data-id")) -
Integer.parseInt(o2.attr("data-id")));
for (int i = 0; i < aDiv.size(); i++) {
Element dd = aDiv.get(i);
if (i == aDiv.size() - 1) break;
sb.append(Html.fromHtml(dd.html()).toString());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -138,24 +134,24 @@ public class XiaGuReadCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("subject-list").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis){
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("【最新章节】", ""));
book.setDesc(li.getElementsByTag("p").first().text());
String imgUrl = li.getElementsByTag("img").attr("data-original");
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl);
//https://www.xiagu.org/xs/5584.html -> https://www.xiagu.org/read/5/5584/
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("xs", "read/1").replace(".html", "/"));
book.setSource(BookSource.xiagu.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Element div = doc.getElementsByClass("subject-list").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis) {
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(as.get(2).text());
book.setType(as.get(3).text());
book.setNewestChapterTitle(as.get(4).text().replace("【最新章节】", ""));
book.setDesc(li.getElementsByTag("p").first().text());
String imgUrl = li.getElementsByTag("img").attr("data-original");
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl);
//https://www.xiagu.org/xs/5584.html -> https://www.xiagu.org/read/5/5584/
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("xs", "read/1").replace(".html", "/"));
book.setSource(BookSource.xiagu.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }

@ -58,15 +58,11 @@ public class XingXingReadCrawler implements ReadCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("txt");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -131,23 +127,23 @@ public class XingXingReadCrawler implements ReadCrawler {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
// try {
Element div = doc.getElementsByClass("leftBox").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis){
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(li.getElementsByTag("span").first().text());
book.setType(as.get(2).text());
book.setNewestChapterTitle(as.get(3).text());
book.setDesc(li.getElementsByClass("c").first().text().replace("内容介绍:", ""));
book.setUpdateDate(li.getElementsByClass("time2").first().text().replace("更新时间:", ""));
book.setImgUrl(li.getElementsByTag("img").attr("data-original"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace(".html", "/"));
book.setSource(BookSource.xingxing.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Element div = doc.getElementsByClass("leftBox").first();
Elements lis = div.getElementsByTag("li");
for (Element li : lis) {
Elements as = li.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setAuthor(li.getElementsByTag("span").first().text());
book.setType(as.get(2).text());
book.setNewestChapterTitle(as.get(3).text());
book.setDesc(li.getElementsByClass("c").first().text().replace("内容介绍:", ""));
book.setUpdateDate(li.getElementsByClass("time2").first().text().replace("更新时间:", ""));
book.setImgUrl(li.getElementsByTag("img").attr("data-original"));
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace(".html", "/"));
book.setSource(BookSource.xingxing.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }

@ -58,68 +58,65 @@ public class YanQingLouReadCrawler implements ReadCrawler {
}
/*
var preview_page = "/lishi/220987/60.html";
var next_page = "/lishi/220987/62.html";
var index_page = "/lishi/220987/";
var article_id = "220987";
var chapter_id = "61";
var nextcid = "62";
var prevcid = "60";
var articlename = "临高启明";
var chaptername = "第十五节 遇伏";
var hash = "38e338d183600e17";
var localpre = "www.yanqinglou.com";
*/
/**
* 从html中获取章节正文
*
* @param html
* @return
var preview_page = "/lishi/220987/60.html";
var next_page = "/lishi/220987/62.html";
var index_page = "/lishi/220987/";
var article_id = "220987";
var chapter_id = "61";
var nextcid = "62";
var prevcid = "60";
var articlename = "临高启明";
var chaptername = "第十五节 遇伏";
var hash = "38e338d183600e17";
var localpre = "www.yanqinglou.com";
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ")
.replaceAll("您可以.*最新章节!", "")
.replaceAll("转码页面.*com/", "");
return content;
} else {
return "";
String content = "";
content = Html.fromHtml(divContent.html()).toString();
try {
if (content.contains("正在加载") || content.contains("本章未完,点击下一页继续阅读")) {
content = getAjaxContent(html);
}
/*if (content.contains("本章未完,点击下一页继续阅读")){
String nextUrl = doc.select(".to_nextpage")
.first().select("a").first()
.attr("href");
content = content.replace("本章未完,点击下一页继续阅读", "")
.replace("-->>", "");
content += getContentFormHtml(OkHttpUtils.getHtml(NAME_SPACE + nextUrl, CHARSET));
}*/
} catch (IOException | JSONException e) {
e.printStackTrace();
}
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ")
.replaceAll("您可以.*最新章节!", "")
.replaceAll("转码页.*com/", "");
return content;
}
/*
id: 220987
eKey: fe9535a08b53e929
cid: 62
basecid: 62
*/
public void getAjaxContent(String html, ResultCallback callback){
public String getAjaxContent(String html) throws IOException, JSONException {
String id = StringUtils.getSubString(html, "var article_id = \"", "\";");
String eKey = StringUtils.getSubString(html, "var hash = \"", "\";");
String cid = StringUtils.getSubString(html, "var chapter_id = \"", "\";");
String body = "id=" + id + "&eKey=" + eKey + "&cid=" + cid + "&basecid=" + cid;
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody requestBody = RequestBody.create(mediaType, body);
try {
String jsonStr = OkHttpUtils.getHtml(AJAX_CONTENT, requestBody, CHARSET);
JSONObject json = new JSONObject(jsonStr);
String content = json.getJSONObject("info").getString("content");
content = Html.fromHtml(content).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ")
.replaceAll("您可以.*最新章节!", "")
.replaceAll("转码页面.*com/", "");
callback.onFinish(content, 0);
} catch (IOException | JSONException e) {
e.printStackTrace();
callback.onError(e);
}
String jsonStr = OkHttpUtils.getHtml(AJAX_CONTENT, requestBody, CHARSET);
JSONObject json = new JSONObject(jsonStr);
String content = json.getJSONObject("info").getString("content");
content = Html.fromHtml(content).toString();
return content;
}
/**
@ -148,18 +145,18 @@ public class YanQingLouReadCrawler implements ReadCrawler {
/**
* 从搜索html中得到书列表
<div class="bookbox">
<div class="p10"><span class="num"> <a title="斗罗之大主宰" href="/hunlian/459337/"><img layout="fixed" width="90" height="120" src="https://www.biquduo.com/files/article/image/64/64075/64075s.jpg" alt="斗罗之大主宰" /></a> </span>
<div class="bookinfo">
<h4 class="bookname"><a title="斗罗之大主宰" href="/hunlian/459337/">斗罗之大主宰</a></h4>
<div class="author">作者<a href="/writter/%E4%B8%8A%E5%BC%A6666.html" target="_blank" title="上弦666的作品大全">上弦666</a></div>
<div class="author">分类婚恋</div>
<div class="cat"><span>更新到</span><a href="/hunlian/459337/">最近更新>></a></div>
<div class="update"><span>简介</span>叶辰武魂昊天锤的变异大须弥锤昊天锤本就是大陆第一器武魂而武魂是大须弥锤的叶辰会有多强</div>
</div>
<div class="delbutton"> <a class="del_but" title="斗罗之大主宰" href="/hunlian/459337/">阅读</a></div>
</div>
</div>
* <div class="bookbox">
* <div class="p10"><span class="num"> <a title="斗罗之大主宰" href="/hunlian/459337/"><img layout="fixed" width="90" height="120" src="https://www.biquduo.com/files/article/image/64/64075/64075s.jpg" alt="斗罗之大主宰" /></a> </span>
* <div class="bookinfo">
* <h4 class="bookname"><a title="斗罗之大主宰" href="/hunlian/459337/">斗罗之大主宰</a></h4>
* <div class="author">作者<a href="/writter/%E4%B8%8A%E5%BC%A6666.html" target="_blank" title="上弦666的作品大全">上弦666</a></div>
* <div class="author">分类婚恋</div>
* <div class="cat"><span>更新到</span><a href="/hunlian/459337/">最近更新>></a></div>
* <div class="update"><span>简介</span>叶辰武魂昊天锤的变异大须弥锤昊天锤本就是大陆第一器武魂而武魂是大须弥锤的叶辰会有多强</div>
* </div>
* <div class="delbutton"> <a class="del_but" title="斗罗之大主宰" href="/hunlian/459337/">阅读</a></div>
* </div>
* </div>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
@ -182,7 +179,7 @@ public class YanQingLouReadCrawler implements ReadCrawler {
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}else {
} else {
Book book = new Book();
getBookInfo(doc, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());

@ -5,6 +5,7 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -56,20 +57,16 @@ public class YunZhongReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementsByClass("box_box").first();
if (divContent != null) {
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()){
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
StringBuilder sb = new StringBuilder();
for (TextNode textNode : divContent.textNodes()) {
sb.append(textNode.text());
sb.append("\n");
}
String content = sb.toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**
@ -110,23 +107,23 @@ public class YunZhongReadCrawler implements ReadCrawler, BookInfoCrawler {
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
// try {
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("ul_b_list");
Element div = divs.get(0);
Elements elementsByTag = div.getElementsByTag("li");
for (Element element : elementsByTag) {
Book book = new Book();
Element info = element.getElementsByTag("h2").first();
book.setName(info.getElementsByTag("a").first().text());
book.setType(info.getElementsByTag("span").first().text());
book.setAuthor(element.getElementsByClass("state").first().text().replaceAll("作者.|类型.*", ""));
book.setImgUrl(NAME_SPACE + element.getElementsByClass("pic").first().getElementsByTag("img").first().attr("src"));
book.setChapterUrl(NAME_SPACE + element.getElementsByTag("a").first().attr("href"));
book.setNewestChapterTitle("");
book.setSource(BookSource.yunzhong.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("ul_b_list");
Element div = divs.get(0);
Elements elementsByTag = div.getElementsByTag("li");
for (Element element : elementsByTag) {
Book book = new Book();
Element info = element.getElementsByTag("h2").first();
book.setName(info.getElementsByTag("a").first().text());
book.setType(info.getElementsByTag("span").first().text());
book.setAuthor(element.getElementsByClass("state").first().text().replaceAll("作者.|类型.*", ""));
book.setImgUrl(NAME_SPACE + element.getElementsByClass("pic").first().getElementsByTag("img").first().attr("src"));
book.setChapterUrl(NAME_SPACE + element.getElementsByTag("a").first().attr("href"));
book.setNewestChapterTitle("");
book.setSource(BookSource.yunzhong.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
// } catch (Exception e) {
// e.printStackTrace();
// }

@ -0,0 +1,170 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class ZW37ReadCrawler implements ReadCrawler, BookInfoCrawler {
private static final String NAME_SPACE = "https://www.37zww.net";
private static final String NOVEL_SEARCH = "https://www.37zww.net/modules/article/search.php?searchtype=articlename&searchkey={key}";
private static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "GBK";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return false;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
@Override
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
@Override
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Element divList = doc.getElementById("list");
String lastTile = null;
int i = 0;
Elements elementsByTag = divList.getElementsByTag("a");
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
if (!StringHelper.isEmpty(lastTile) && title.equals(lastTile)) {
continue;
}
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
String url = readUrl + a.attr("href");
chapter.setUrl(url);
chapters.add(chapter);
lastTile = title;
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <tr>
* <td class="odd"><a href="https://www.37zww.net/1/1812/">斗罗大陆IV终极斗罗</a></td>
* <td class="even"><a href="https://www.37zww.net/1/1812/index.html" target="_blank"> 第一千五百八十一章 突破真神级</a></td>
* <td class="odd">唐家三少</td>
* <td class="even">8427K</td>
* <td class="odd" align="center">21-02-06</td>
* <td class="even" align="center">连载</td>
* </tr>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
final ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(html, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Element div = doc.getElementById("main");
Elements elements = div.getElementsByTag("tr");
for (int i = 1; i < elements.size(); i++) {
Element element = elements.get(i);
Book book = new Book();
Elements info = element.getElementsByTag("td");
book.setName(info.get(0).text());
book.setChapterUrl(info.get(0).selectFirst("a").attr("href"));
book.setAuthor(info.get(2).text());
book.setNewestChapterTitle(info.get(1).text());
book.setSource(BookSource.zw37.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
return books;
}
/**
* 获取小说详细信息
*
* @param html
* @return
*/
public Book getBookInfo(String html, Book book) {
Document doc = Jsoup.parse(html);
book.setSource(BookSource.zw37.toString());
String name = doc.select("meta[property=og:title]").attr("content");
book.setName(name);
String url = doc.select("meta[property=og:novel:read_url]").attr("content");
book.setChapterUrl(url);
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
String newestChapter = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapter);
String img = doc.select("meta[property=og:image]").attr("content");
book.setImgUrl(img);
String desc = doc.select("meta[property=og:description]").attr("content");
book.setDesc(desc);
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
return book;
}
}

@ -0,0 +1,161 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.webapi.crawler.base.FindCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class ZaiShuYuanReadCrawler implements ReadCrawler {
public static final String NAME_SPACE = "https://www.zhaishuyuan.com";
public static final String NOVEL_SEARCH = "https://www.zhaishuyuan.com/search/,key={key}";
public static final String CHARSET = "gbk";
public static final String SEARCH_CHARSET = "gbk";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public Boolean isPost() {
return true;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*
* @param html
* @return
*/
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("content");
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ").replaceAll("您可以在.*最新章节!|\\\\", "");
return content;
}
/**
* 从html中获取章节列表
*
* @param html
* @return
*/
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
Element divList = doc.getElementById("readerlist");
Elements elementsByTag = divList.getElementsByTag("a");
int i = 0;
for (int j = 0; j < elementsByTag.size(); j++) {
Element a = elementsByTag.get(j);
String title = a.text();
String url = a.attr("href");
Chapter chapter = new Chapter();
chapter.setNumber(i++);
chapter.setTitle(title);
chapter.setUrl(NAME_SPACE + url);
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return <dl>
* <dt><a href="/book/3"><img class="lazyload" _src="https://img.zhaishuyuan.com/bookpic/s3.jpg" alt="<font color=#F30>大主宰</font>" height="155" width="120"></a></dt>
* <dd><h3><a href="/read/3"><font color=#F30>大主宰</font></a><span class="alias">别名<font color=#F30>大主宰</font></span></h3></dd>
* <dd class="book_other">作者<span>天蚕土豆</span>状态<span>已完结</span>小类<span>异世大陆</span>字数<span>4944063</span>标签<a href="/search/?key=%C8%C8%D1%AA" target="_blank" rel="nofollow">热血</a> <a href="/search/?key=%CB%AC%CE%C4" target="_blank" rel="nofollow">爽文</a></dd>
* <dd class="book_des">大千世界位面交汇万族林立群雄荟萃一位位来自下位面的天之至尊在这无尽世界演绎着令人向往的传奇追求着那主宰之路无尽火域炎帝执掌万火焚苍穹武境之内武祖之威震慑乾坤西天之殿百战之皇战威无可敌北荒之丘万墓之地不死</dd>
* <dd class="book_other">最新章节<a href="/chapter/3/8855386">第一千五百五十一章 邪神陨落大结局</a> 更新时间<span>2020-2-26 13:26:49</span></dd>
* </dl>
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(doc, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Element div = doc.getElementById("sitembox");
Elements dls = div.getElementsByTag("dl");
for (Element dl : dls) {
Elements as = dl.getElementsByTag("a");
Book book = new Book();
book.setName(as.get(1).text());
book.setImgUrl(as.first().getElementsByTag("img").attr("_src"));
book.setNewestChapterTitle(as.last().text());
Elements spans = dl.selectFirst(".book_other").select("span");
book.setAuthor(spans.get(0).text());
book.setType(spans.get(2).text());
book.setDesc(dl.getElementsByClass("book_des").first().text());
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("novel", "read").replace(".html", "/"));
book.setSource(BookSource.zaishuyuan.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
return books;
}
private void getBookInfo(Document doc, Book book) {
book.setSource(BookSource.zaishuyuan.toString());
String name = doc.select("meta[property=og:title]").attr("content");
book.setName(name);
String url = doc.select("meta[property=og:novel:read_url]").attr("content");
book.setChapterUrl(url);
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
String newestChapter = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapter);
String img = doc.select("meta[property=og:image]").attr("content");
book.setImgUrl(img);
Element desc = doc.getElementById("bookintro");
book.setDesc(Html.fromHtml(desc.html()).toString());
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
}
}

@ -1,10 +1,12 @@
package xyz.fycz.myreader.webapi.crawler.read;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -56,15 +58,11 @@ public class ZuoPinReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divContent = doc.getElementById("htmlContent");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
} else {
return "";
}
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
return content;
}
/**

@ -282,7 +282,7 @@ public class LocalPageLoader extends PageLoader {
@Override
public void onError(Throwable e) {
resultCallback.onError((Exception) e);
chapterError();
chapterError(e.getLocalizedMessage());
Log.d(TAG, "file load error:" + e.toString());
}
});

@ -1,29 +1,30 @@
package xyz.fycz.myreader.widget.page;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.webapi.CommonApi;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import xyz.fycz.myreader.webapi.callback.ResultCallback;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class NetPageLoader extends PageLoader {
private static final String TAG = "PageFactory";
private ChapterService mChapterService;
private ReadCrawler mReadCrawler;
private List<Chapter> loadingChapters = new CopyOnWriteArrayList<>();
public NetPageLoader(PageView pageView, Book collBook, ChapterService mChapterService,
ReadCrawler mReadCrawler, Setting setting) {
@ -98,7 +99,10 @@ public class NetPageLoader extends PageLoader {
boolean parseCurChapter() {
boolean isRight = super.parseCurChapter();
if (mStatus == STATUS_LOADING) {
if (mStatus == STATUS_FINISH) {
loadPrevChapter();
loadNextChapter();
} else if (mStatus == STATUS_LOADING) {
loadCurrentChapter();
}
return isRight;
@ -195,15 +199,16 @@ public class NetPageLoader extends PageLoader {
List<Chapter> chapters = new ArrayList<>();
// 过滤,哪些数据已经加载了
// 过滤,哪些数据已经加载了/正在加载
for (int i = start; i <= end; ++i) {
Chapter txtChapter = mChapterList.get(i);
if (!hasChapterData(txtChapter)) {
if (!hasChapterData(txtChapter) && !loadingChapters.contains(txtChapter)) {
chapters.add(txtChapter);
}
}
if (!chapters.isEmpty()) {
loadingChapters.addAll(chapters);
for (Chapter chapter : chapters) {
getChapterContent(chapter);
}
@ -219,8 +224,10 @@ public class NetPageLoader extends PageLoader {
CommonApi.getChapterContent(chapter.getUrl(), mReadCrawler, new ResultCallback() {
@Override
public void onFinish(final Object o, int code) {
loadingChapters.remove(chapter);
mChapterService.saveOrUpdateChapter(chapter, (String) o);
if (getPageStatus() == PageLoader.STATUS_LOADING) {
if (isClose()) return;
if (getPageStatus() == PageLoader.STATUS_LOADING && mCurChapterPos == chapter.getNumber()) {
MyApplication.runOnUiThread(() -> {
if (isPrev) {
openChapterInLastPage();
@ -233,8 +240,10 @@ public class NetPageLoader extends PageLoader {
@Override
public void onError(Exception e) {
loadingChapters.remove(chapter);
if (isClose()) return;
if (mCurChapterPos == chapter.getNumber())
chapterError();
chapterError("请尝试重新加载或换源\n" + e.getLocalizedMessage());
e.printStackTrace();
}
});

@ -17,6 +17,7 @@ import com.gyf.immersionbar.ImmersionBar;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
@ -62,6 +63,8 @@ public abstract class PageLoader {
public static final int STATUS_PARING = 6; // 正在解析 (装载本地数据)
public static final int STATUS_PARSE_ERROR = 7; // 本地文件解析错误(暂未被使用)
public static final int STATUS_CATEGORY_EMPTY = 8; // 获取到的目录为空
private String errorMsg = "";
// 默认的显示参数配置
public static final int DEFAULT_MARGIN_HEIGHT = 28;
public static final int DEFAULT_MARGIN_WIDTH = 15;
@ -106,7 +109,9 @@ public abstract class PageLoader {
// private BookRecordBean mBookRecord;
//缩进
String indent;
private Disposable mPreLoadDisp;
private Disposable mPreLoadNextDisp;
private Disposable mPreLoadPrevDisp;
private CompositeDisposable compositeDisposable;
/*****************params**************************/
// 当前的状态
@ -175,6 +180,7 @@ public abstract class PageLoader {
mContext = pageView.getContext();
mCollBook = collBook;
mChapterList = new ArrayList<>(1);
compositeDisposable = new CompositeDisposable();
// 获取配置管理器
mSettingManager = setting;
// 初始化数据
@ -367,8 +373,11 @@ public abstract class PageLoader {
// 将上一章的缓存设置为null
mPreChapter = null;
// 如果当前下一章缓存正在执行,则取消
if (mPreLoadDisp != null) {
mPreLoadDisp.dispose();
if (mPreLoadNextDisp != null) {
mPreLoadNextDisp.dispose();
}
if (mPreLoadPrevDisp != null) {
mPreLoadPrevDisp.dispose();
}
// 将下一章缓存设置为null
mNextChapter = null;
@ -769,9 +778,10 @@ public abstract class PageLoader {
mPageView.drawCurPage(false);
}
public void chapterError() {
public void chapterError(String msg) {
//加载错误
mStatus = STATUS_ERROR;
errorMsg = msg;
mPageView.drawCurPage(false);
}
@ -782,8 +792,11 @@ public abstract class PageLoader {
isChapterListPrepare = false;
isClose = true;
if (mPreLoadDisp != null) {
mPreLoadDisp.dispose();
if (mPreLoadNextDisp != null) {
mPreLoadNextDisp.dispose();
}
if (mPreLoadPrevDisp != null) {
mPreLoadPrevDisp.dispose();
}
clearList(mChapterList);
@ -1014,7 +1027,7 @@ public abstract class PageLoader {
tip = "正在加载目录列表...";
break;
case STATUS_ERROR:
tip = "章节内容加载失败";
tip = "章节内容加载失败\n" + errorMsg;
break;
case STATUS_EMPTY:
tip = "章节内容为空";
@ -1029,14 +1042,17 @@ public abstract class PageLoader {
tip = "目录列表为空";
break;
}
//将提示语句放到正中间
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float textHeight = fontMetrics.top - fontMetrics.bottom;
float textWidth = mTextPaint.measureText(tip);
float pivotX = (mDisplayWidth - textWidth) / 2;
float pivotY = (mDisplayHeight - textHeight) / 2;
canvas.drawText(tip, pivotX, pivotY, mTextPaint);
if (mStatus == STATUS_ERROR) {
drawErrorMsg(canvas, tip, 0);
} else {
//将提示语句放到正中间
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float textHeight = fontMetrics.top - fontMetrics.bottom;
float textWidth = mTextPaint.measureText(tip);
float pivotX = (mDisplayWidth - textWidth) / 2;
float pivotY = (mDisplayHeight - textHeight) / 2;
canvas.drawText(tip, pivotX, pivotY, mTextPaint);
}
} else {
float top;
if (mPageMode == PageMode.SCROLL) {
@ -1224,6 +1240,22 @@ public abstract class PageLoader {
}
}
private void drawErrorMsg(Canvas canvas, String msg, float offset) {
float textInterval = mTextInterval + mTextPaint.getTextSize();
Layout tempLayout = new StaticLayout(msg, mTextPaint, mVisibleWidth, Layout.Alignment.ALIGN_NORMAL, 0, 0, false);
List<String> linesData = new ArrayList<>();
for (int i = 0; i < tempLayout.getLineCount(); i++) {
linesData.add(msg.substring(tempLayout.getLineStart(i), tempLayout.getLineEnd(i)));
}
float pivotY = (mDisplayHeight - textInterval * linesData.size()) / 2f - offset;
for (String str : linesData) {
float textWidth = mTextPaint.measureText(str);
float pivotX = (mDisplayWidth - textWidth) / 2;
canvas.drawText(str, pivotX, pivotY, mTextPaint);
pivotY += textInterval;
}
}
//判断是不是d'hou
private boolean isFirstLineOfParagraph(String line) {
return line.length() > 3 && line.charAt(0) == (char) 12288 && line.charAt(1) == (char) 12288;
@ -1343,6 +1375,8 @@ public abstract class PageLoader {
} else {
dealLoadPageList(prevChapter);
}
// 预加载上一页面
preLoadPrevChapter();
return mCurChapter != null;
}
@ -1404,7 +1438,8 @@ public abstract class PageLoader {
boolean parseCurChapter() {
// 解析数据
dealLoadPageList(mCurChapterPos);
// 预加载下一页面
// 预加载上一页和下一页面
preLoadPrevChapter();
preLoadNextChapter();
return mCurChapter != null;
}
@ -1475,6 +1510,41 @@ public abstract class PageLoader {
}
}
// 预加载上一章
private void preLoadPrevChapter() {
int prevChapter = mCurChapterPos - 1;
// 如果不存在下一章,且下一章没有数据,则不进行加载。
if (!hasPrevChapter()
|| !hasChapterData(mChapterList.get(prevChapter))) {
return;
}
//如果之前正在加载则取消
if (mPreLoadPrevDisp != null) {
mPreLoadPrevDisp.dispose();
}
//调用异步进行预加载加载
Single.create((SingleOnSubscribe<TxtChapter>) e -> e.onSuccess(loadPageList(prevChapter)))
.compose(RxUtils::toSimpleSingle)
.subscribe(new SingleObserver<TxtChapter>() {
@Override
public void onSubscribe(Disposable d) {
mPreLoadPrevDisp = d;
}
@Override
public void onSuccess(TxtChapter txtChapter) {
mPreChapter = txtChapter;
}
@Override
public void onError(Throwable e) {
//无视错误
}
});
}
// 预加载下一章
private void preLoadNextChapter() {
int nextChapter = mCurChapterPos + 1;
@ -1485,8 +1555,8 @@ public abstract class PageLoader {
return;
}
//如果之前正在加载则取消
if (mPreLoadDisp != null) {
mPreLoadDisp.dispose();
if (mPreLoadNextDisp != null) {
mPreLoadNextDisp.dispose();
}
//调用异步进行预加载加载
@ -1495,7 +1565,7 @@ public abstract class PageLoader {
.subscribe(new SingleObserver<TxtChapter>() {
@Override
public void onSubscribe(Disposable d) {
mPreLoadDisp = d;
mPreLoadNextDisp = d;
}
@Override

@ -1,52 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorBackground"
android:fitsSystemWindows="true"
tools:context="xyz.fycz.myreader.ui.activity.SearchBookActivity">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBackground"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context="xyz.fycz.myreader.ui.activity.SearchBookActivity">
<include layout="@layout/toolbar" />
<include layout="@layout/toolbar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp">
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingRight="15dp"
android:paddingBottom="10dp">
<EditText
android:id="@+id/et_search_key"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_weight="2"
android:background="@drawable/search_et_backcolor"
android:hint="输入关键词"
android:paddingLeft="10dp"
android:textColor="@color/textPrimary"
android:imeOptions="actionSearch"
/>
android:id="@+id/et_search_key"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_weight="2"
android:background="@drawable/search_et_backcolor"
android:hint="输入关键词"
android:imeOptions="actionSearch"
android:paddingLeft="10dp"
android:textColor="@color/textPrimary" />
<TextView
android:id="@+id/tv_search_conform"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_weight="8"
android:background="@drawable/search_btn_backcolor"
android:gravity="center"
android:text="搜索"
android:textColor="@color/textPrimaryInverted"
android:textSize="18sp"/>
android:id="@+id/tv_search_conform"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_weight="8"
android:background="@drawable/search_btn_backcolor"
android:gravity="center"
android:text="搜索"
android:textColor="@color/textPrimaryInverted"
android:textSize="18sp" />
</LinearLayout>
<RadioGroup
android:id="@+id/rg_search_filter"
android:layout_width="match_parent"
@ -58,78 +58,82 @@
android:id="@+id/rb_all_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size"
android:checked="true"
android:text="@string/all" />
android:text="@string/all"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size" />
<androidx.appcompat.widget.AppCompatRadioButton
android:id="@+id/rb_fuzzy_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size"
android:layout_marginStart="10dp"
android:checked="true"
android:text="@string/fuzzy_search" />
android:text="@string/fuzzy_search"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size" />
<androidx.appcompat.widget.AppCompatRadioButton
android:id="@+id/rb_precise_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size"
android:layout_marginStart="10dp"
android:text="@string/precise_search" />
android:text="@string/precise_search"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size" />
</RadioGroup>
<xyz.fycz.myreader.widget.RefreshProgressBar
android:id="@+id/rpb"
android:layout_width="match_parent"
android:layout_height="3dp"
android:visibility="visible"/>
android:id="@+id/rpb"
android:layout_width="match_parent"
android:layout_height="3dp"
android:visibility="visible" />
<LinearLayout
android:id="@+id/ll_suggest_books_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorForeground"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
android:id="@+id/ll_suggest_books_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorForeground"
android:gravity="center"
android:orientation="vertical"
android:padding="5dp">
<me.gujun.android.taggroup.TagGroup
android:id="@+id/tg_suggest_book"
style="@style/TagGroup"
android:layout_marginTop="10dp"
app:atg_pressedBackgroundColor="@color/colorForeground"
app:atg_backgroundColor="@color/background_card"
app:atg_borderColor="@color/background_card"
app:atg_horizontalPadding="10dp"
app:atg_textColor="@color/textPrimary"
app:atg_textSize="14sp"
app:atg_verticalSpacing="10dp"/>
android:id="@+id/tg_suggest_book"
style="@style/TagGroup"
android:layout_marginTop="5dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
app:atg_backgroundColor="@color/colorBackground"
app:atg_borderColor="@color/colorForeground"
app:atg_horizontalPadding="5dp"
app:atg_pressedBackgroundColor="@color/colorForeground"
app:atg_textColor="@color/textPrimary"
app:atg_textSize="14sp"
app:atg_verticalSpacing="5dp" />
<LinearLayout
android:id="@+id/ll_refresh_suggest_books"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="horizontal">
android:id="@+id/ll_refresh_suggest_books"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/renew_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_refresh"
app:tint="@color/textPrimary"/>
android:id="@+id/renew_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_refresh"
app:tint="@color/textPrimary" />
<TextView
android:id="@+id/renew_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="换一批"
android:textColor="@color/textPrimary"
android:textSize="14sp"/>
android:id="@+id/renew_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="换一批"
android:textColor="@color/textPrimary"
android:textSize="14sp" />
</LinearLayout>
@ -138,62 +142,66 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_history_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorForeground"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp">
android:id="@+id/ll_history_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorForeground"
android:gravity="center"
android:orientation="vertical"
android:padding="5dp">
<ListView
android:id="@+id/lv_history_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:divider="@color/nothing"
android:fadingEdge="none"
android:overScrollMode="never"
android:scrollbars="none">
android:id="@+id/lv_history_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/nothing"
android:fadingEdge="none"
android:overScrollMode="never"
android:scrollbars="none">
</ListView>
<LinearLayout
android:id="@+id/ll_clear_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
android:id="@+id/ll_clear_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
app:tint="@color/textPrimary"
app:srcCompat="@drawable/ic_clear"/>
android:layout_width="20dp"
android:layout_height="20dp"
app:srcCompat="@drawable/ic_clear"
app:tint="@color/textPrimary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清空历史记录"
android:textColor="@color/textPrimary"
android:textSize="14sp"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清空历史记录"
android:textColor="@color/textPrimary"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_search_book_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="3">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_search_book_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants">
android:descendantFocusability="blocksDescendants">
<com.scwang.smartrefresh.header.MaterialHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!--<ListView
android:id="@+id/lv_search_books_list"
android:layout_width="match_parent"
@ -212,26 +220,26 @@
android:padding="5dp">
</xyz.fycz.myreader.custom.DragSortGridView>-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_search_books_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:visibility="visible" />
android:id="@+id/rv_search_books_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:visibility="visible" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabSearchStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="30dp"
android:layout_marginBottom="30dp"
android:src="@drawable/ic_stop_black_24dp"
app:elevation="5dp"
app:fabSize="mini"
app:layout_anchorGravity="right|bottom"
android:visibility="gone"/>
android:id="@+id/fabSearchStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="30dp"
android:layout_marginBottom="30dp"
android:src="@drawable/ic_stop_black_24dp"
android:visibility="gone"
app:elevation="5dp"
app:fabSize="mini"
app:layout_anchorGravity="right|bottom" />
</RelativeLayout>
</LinearLayout>

@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_hot"
android:title="@string/hot_search"
android:visible="false"
app:showAsAction="always" />
<item
android:id="@+id/action_disable_source"
android:title="@string/disable_source"

@ -212,6 +212,12 @@
<string name="read_bijian">笔尖小说</string>
<string name="read_yanqinglou">言情楼</string>
<string name="read_wolong">卧龙小说</string>
<string name="read_ewenxue">E文学</string>
<string name="read_shuhaige">书海阁</string>
<string name="read_luoqiu">落秋中文</string>
<string name="read_zw37">三七中文</string>
<string name="read_xbiquge">新笔趣阁</string>
<string name="read_zaishuyuan">斋书苑</string>
<string name="read_chaoxing">超星图书·实体</string>
<string name="read_zuopin">作品集·实体</string>
<string name="read_cangshu99">99藏书·实体</string>
@ -337,6 +343,7 @@
<string name="help">帮助</string>
<string name="refresh_books">更新目录</string>
<string name="finish">完成</string>
<string name="hot_search">热搜</string>
<string-array name="reset_screen_time">
<item>常亮</item>

@ -17,7 +17,7 @@ yunzhong=xyz.fycz.myreader.webapi.crawler.read.YunZhongReadCrawler
sonovel=xyz.fycz.myreader.webapi.crawler.read.SoNovelReadCrawler
quannovel=xyz.fycz.myreader.webapi.crawler.read.QuanNovelReadCrawler
qiqi=xyz.fycz.myreader.webapi.crawler.read.QiQiReadCrawler
xs7=xyz.fycz.myreader.webapi.crawler.read.XS7ReadCrawler
xs7=xyz.fycz.myreader.webapi.crawler.read.XS7ReadCrawler2
du1du=xyz.fycz.myreader.webapi.crawler.read.Du1DuReadCrawler
paiotian=xyz.fycz.myreader.webapi.crawler.read.PiaoTianReadCrawler
laoyao=xyz.fycz.myreader.webapi.crawler.read.LaoYaoReadCrawler
@ -29,4 +29,10 @@ xiagu=xyz.fycz.myreader.webapi.crawler.read.XiaGuReadCrawler
hongchen=xyz.fycz.myreader.webapi.crawler.read.HongChenReadCrawler
bijian=xyz.fycz.myreader.webapi.crawler.read.BiJianReadCrawler
yanqinglou=xyz.fycz.myreader.webapi.crawler.read.YanQingLouReadCrawler
wolong=xyz.fycz.myreader.webapi.crawler.read.WoLongReadCrawler
wolong=xyz.fycz.myreader.webapi.crawler.read.WoLongReadCrawler
ewenxue=xyz.fycz.myreader.webapi.crawler.read.EWenXueReadCrawler
shuhaige=xyz.fycz.myreader.webapi.crawler.read.ShuHaiGeReadCrawler
luoqiu=xyz.fycz.myreader.webapi.crawler.read.LuoQiuReadCrawler
zw37=xyz.fycz.myreader.webapi.crawler.read.ZW37ReadCrawler
xbiquge=xyz.fycz.myreader.webapi.crawler.read.XBiQuGeReadCrawler
zaishuyuan=xyz.fycz.myreader.webapi.crawler.read.ZaiShuYuanReadCrawler

@ -1,2 +1,2 @@
#Wed Feb 03 13:23:18 CST 2021
VERSION_CODE=181
#Sat Feb 06 19:10:55 CST 2021
VERSION_CODE=182

Loading…
Cancel
Save