parent
3be4cf4fa8
commit
fdea628154
Binary file not shown.
@ -1,212 +0,0 @@ |
||||
package xyz.fycz.myreader.entity; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.ArrayList; |
||||
|
||||
/** |
||||
* Created by zhao on 2016/11/9. |
||||
* APP通迅录树结构 |
||||
* |
||||
*/ |
||||
|
||||
public class ContactsTree implements Serializable { |
||||
|
||||
private static final long serialVersionUID = 7184368467231587092L; |
||||
|
||||
//根节点赋值字段(部门节点)
|
||||
private String DepartId;//部门id
|
||||
private String DepartName;//部门名
|
||||
private String orgCode; //部门编码
|
||||
private String departOrder; //部门排序
|
||||
private boolean select; |
||||
|
||||
//叶节点赋值字段(个人信息节点)
|
||||
private String id; |
||||
private String userDepartId;//用户所属部门ID
|
||||
private String userDepartName;//用户所属部门名
|
||||
private boolean moreDepartUser;// 用户是否多部门 true是 false不是
|
||||
private boolean transpondPerson;//是否转发人员 true是 false不是
|
||||
private String userName;//用户名
|
||||
private String realName;//姓名
|
||||
private String wholeSpellName;//姓名全拼
|
||||
private String firstLetterName;//拼音首字母 eg:hzh
|
||||
private String mobilePhone;//手机
|
||||
private String sex;//性别
|
||||
private String email;//邮箱
|
||||
|
||||
private ArrayList<ContactsTree> children;//孩子节点
|
||||
|
||||
private ContactsTree parent;//父节点
|
||||
|
||||
public boolean isTranspondPerson() { |
||||
return transpondPerson; |
||||
} |
||||
|
||||
public void setTranspondPerson(boolean transpondPerson) { |
||||
this.transpondPerson = transpondPerson; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getDepartOrder() { |
||||
return departOrder; |
||||
} |
||||
|
||||
public String getOrgCode() { |
||||
return orgCode; |
||||
} |
||||
|
||||
public void setDepartOrder(String departOrder) { |
||||
this.departOrder = departOrder; |
||||
} |
||||
|
||||
public void setOrgCode(String orgCode) { |
||||
this.orgCode = orgCode; |
||||
} |
||||
|
||||
public boolean isMoreDepartUser() { |
||||
return moreDepartUser; |
||||
} |
||||
|
||||
public void setMoreDepartUser(boolean moreDepartUser) { |
||||
this.moreDepartUser = moreDepartUser; |
||||
} |
||||
|
||||
public String getUserDepartId() { |
||||
return userDepartId; |
||||
} |
||||
|
||||
public String getUserDepartName() { |
||||
return userDepartName; |
||||
} |
||||
|
||||
public void setUserDepartId(String userDepartId) { |
||||
this.userDepartId = userDepartId; |
||||
} |
||||
|
||||
public void setUserDepartName(String userDepartName) { |
||||
this.userDepartName = userDepartName; |
||||
} |
||||
|
||||
public boolean isSelect() { |
||||
return select; |
||||
} |
||||
|
||||
public void setSelect(boolean select) { |
||||
this.select = select; |
||||
} |
||||
|
||||
public ContactsTree getParent() { |
||||
return parent; |
||||
} |
||||
|
||||
public void setParent(ContactsTree parent) { |
||||
this.parent = parent; |
||||
} |
||||
|
||||
public ContactsTree(){ |
||||
children = new ArrayList<>(); |
||||
} |
||||
|
||||
public String getSex() { |
||||
return sex; |
||||
} |
||||
|
||||
public void setSex(String sex) { |
||||
this.sex = sex; |
||||
} |
||||
|
||||
public String getMobilePhone() { |
||||
return mobilePhone; |
||||
} |
||||
|
||||
public void setMobilePhone(String mobilePhone) { |
||||
this.mobilePhone = mobilePhone; |
||||
} |
||||
|
||||
public ArrayList<ContactsTree> getChildren() { |
||||
return children; |
||||
} |
||||
|
||||
public String getDepartId() { |
||||
return DepartId; |
||||
} |
||||
|
||||
public String getDepartName() { |
||||
return DepartName; |
||||
} |
||||
|
||||
public String getFirstLetterName() { |
||||
return firstLetterName; |
||||
} |
||||
|
||||
public String getRealName() { |
||||
return realName; |
||||
} |
||||
|
||||
public String getUserName() { |
||||
return userName; |
||||
} |
||||
|
||||
public String getWholeSpellName() { |
||||
return wholeSpellName; |
||||
} |
||||
|
||||
public void setChildren(ArrayList<ContactsTree> children) { |
||||
this.children = children; |
||||
} |
||||
|
||||
public void setDepartId(String departId) { |
||||
DepartId = departId; |
||||
} |
||||
|
||||
public void setDepartName(String departName) { |
||||
DepartName = departName; |
||||
} |
||||
|
||||
public void setFirstLetterName(String firstLetterName) { |
||||
this.firstLetterName = firstLetterName; |
||||
} |
||||
|
||||
public void setRealName(String realName) { |
||||
this.realName = realName; |
||||
} |
||||
|
||||
public void setUserName(String userName) { |
||||
this.userName = userName; |
||||
} |
||||
|
||||
public void setWholeSpellName(String wholeSpellName) { |
||||
this.wholeSpellName = wholeSpellName; |
||||
} |
||||
|
||||
public String getEmail() { |
||||
return email; |
||||
} |
||||
|
||||
public void setEmail(String email) { |
||||
this.email = email; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "ContactsTree{" + |
||||
"DepartId='" + DepartId + '\'' + |
||||
", DepartName='" + DepartName + '\'' + |
||||
", userName='" + userName + '\'' + |
||||
", realName='" + realName + '\'' + |
||||
", wholeSpellName='" + wholeSpellName + '\'' + |
||||
", firstLetterName='" + firstLetterName + '\'' + |
||||
", mobilePhone='" + mobilePhone + '\'' + |
||||
", sex='" + sex + '\'' + |
||||
", email='" + email + '\'' + |
||||
", children=" + children + |
||||
'}'; |
||||
} |
||||
} |
@ -1,36 +0,0 @@ |
||||
package xyz.fycz.myreader.entity; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
|
||||
public class Custom implements Serializable { |
||||
|
||||
private static final long serialVersionUID = 5088810102696918656L; |
||||
|
||||
private String id; |
||||
private String type;//类型
|
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public String getType() { |
||||
return type; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public void setType(String type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "Custom{" + |
||||
"id='" + id + '\'' + |
||||
", type='" + type + '\'' + |
||||
'}'; |
||||
} |
||||
} |
@ -1,201 +0,0 @@ |
||||
package xyz.fycz.myreader.entity; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
import java.text.ParseException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
|
||||
|
||||
|
||||
public class Time implements Parcelable{ |
||||
private int year; |
||||
private int month; |
||||
private int date; |
||||
private int hour; |
||||
private int minute; |
||||
private int second; |
||||
|
||||
public long getLongTime(){ |
||||
StringBuilder stringBuilder = new StringBuilder(); |
||||
stringBuilder.append(year); |
||||
if(month < 10){ |
||||
stringBuilder.append("0"+month); |
||||
}else { |
||||
stringBuilder.append(month); |
||||
} |
||||
if(date < 10){ |
||||
stringBuilder.append("0" + date); |
||||
}else { |
||||
stringBuilder.append(date); |
||||
} |
||||
if(hour < 10){ |
||||
stringBuilder.append("0" + hour); |
||||
}else { |
||||
stringBuilder.append(hour); |
||||
} |
||||
if(minute < 10){ |
||||
stringBuilder.append("0" + minute); |
||||
}else { |
||||
stringBuilder.append(minute); |
||||
} |
||||
if(second < 10){ |
||||
stringBuilder.append("0" + second); |
||||
}else { |
||||
stringBuilder.append(second); |
||||
} |
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); |
||||
java.util.Date date = null; |
||||
try { |
||||
date = sdf.parse(stringBuilder.toString()); |
||||
return date.getTime(); |
||||
} catch (ParseException e) { |
||||
e.printStackTrace(); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
|
||||
public void init(Date date){ |
||||
year = date.getYear() + 1900; |
||||
month = date.getMonth() + 1; |
||||
this.date = date.getDate(); |
||||
hour = date.getHours(); |
||||
minute = date.getMinutes(); |
||||
second = 0; |
||||
} |
||||
|
||||
public void init(xyz.fycz.myreader.entity.Date date){ |
||||
Date date1 = new Date(); |
||||
year = date.getYear(); |
||||
month = date.getMonth(); |
||||
this.date = date.getDate(); |
||||
hour = date1.getHours(); |
||||
minute = date1.getMinutes(); |
||||
second = 0; |
||||
} |
||||
|
||||
public void setToDayZero(){ |
||||
hour = 0; |
||||
minute = 0; |
||||
second = 0; |
||||
} |
||||
|
||||
public void setToDayLast(){ |
||||
hour = 23; |
||||
minute = 59; |
||||
second = 59; |
||||
} |
||||
|
||||
public void lastMonth(){ |
||||
if(month == 1){ |
||||
month = 12; |
||||
year = year - 1; |
||||
}else { |
||||
month = month - 1; |
||||
} |
||||
} |
||||
|
||||
public void nextMonth(){ |
||||
if(month == 12){ |
||||
month = 1; |
||||
year = year + 1; |
||||
}else { |
||||
month = month + 1; |
||||
} |
||||
} |
||||
|
||||
public void init(long time){ |
||||
Date date = new Date(time); |
||||
init(date); |
||||
} |
||||
|
||||
|
||||
public int getDate() { |
||||
return date; |
||||
} |
||||
|
||||
public int getHour() { |
||||
return hour; |
||||
} |
||||
|
||||
public int getMinute() { |
||||
return minute; |
||||
} |
||||
|
||||
public int getMonth() { |
||||
return month; |
||||
} |
||||
|
||||
public int getSecond() { |
||||
return second; |
||||
} |
||||
|
||||
public int getYear() { |
||||
return year; |
||||
} |
||||
|
||||
public void setDate(int date) { |
||||
this.date = date; |
||||
} |
||||
|
||||
public void setHour(int hour) { |
||||
this.hour = hour; |
||||
} |
||||
|
||||
public void setMinute(int minute) { |
||||
this.minute = minute; |
||||
} |
||||
|
||||
public void setMonth(int month) { |
||||
this.month = month; |
||||
} |
||||
|
||||
public void setSecond(int second) { |
||||
this.second = second; |
||||
} |
||||
|
||||
public void setYear(int year) { |
||||
this.year = year; |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel dest, int flags) { |
||||
dest.writeInt(this.year); |
||||
dest.writeInt(this.month); |
||||
dest.writeInt(this.date); |
||||
dest.writeInt(this.hour); |
||||
dest.writeInt(this.minute); |
||||
dest.writeInt(this.second); |
||||
} |
||||
|
||||
public Time() { |
||||
} |
||||
|
||||
protected Time(Parcel in) { |
||||
this.year = in.readInt(); |
||||
this.month = in.readInt(); |
||||
this.date = in.readInt(); |
||||
this.hour = in.readInt(); |
||||
this.minute = in.readInt(); |
||||
this.second = in.readInt(); |
||||
} |
||||
|
||||
public static final Creator<Time> CREATOR = new Creator<Time>() { |
||||
@Override |
||||
public Time createFromParcel(Parcel source) { |
||||
return new Time(source); |
||||
} |
||||
|
||||
@Override |
||||
public Time[] newArray(int size) { |
||||
return new Time[size]; |
||||
} |
||||
}; |
||||
} |
@ -1,37 +0,0 @@ |
||||
package xyz.fycz.myreader.entity; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
|
||||
public class UpdateInfo implements Serializable{ |
||||
|
||||
private static final long serialVersionUID = 8136214121542689902L; |
||||
|
||||
private int newestVersionCode; |
||||
private String newestVersionName; |
||||
private String downLoadUrl; |
||||
|
||||
public int getNewestVersionCode() { |
||||
return newestVersionCode; |
||||
} |
||||
|
||||
public void setNewestVersionCode(int newestVersionCode) { |
||||
this.newestVersionCode = newestVersionCode; |
||||
} |
||||
|
||||
public String getNewestVersionName() { |
||||
return newestVersionName; |
||||
} |
||||
|
||||
public void setNewestVersionName(String newestVersionName) { |
||||
this.newestVersionName = newestVersionName; |
||||
} |
||||
|
||||
public String getDownLoadUrl() { |
||||
return downLoadUrl; |
||||
} |
||||
|
||||
public void setDownLoadUrl(String downLoadUrl) { |
||||
this.downLoadUrl = downLoadUrl; |
||||
} |
||||
} |
@ -1,200 +0,0 @@ |
||||
package xyz.fycz.myreader.model.audio; |
||||
|
||||
import android.app.Service; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.os.Build; |
||||
import android.os.IBinder; |
||||
import android.speech.tts.TextToSpeech; |
||||
import android.speech.tts.UtteranceProgressListener; |
||||
import android.text.TextUtils; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
|
||||
import xyz.fycz.myreader.util.ToastUtils; |
||||
|
||||
import static android.text.TextUtils.isEmpty; |
||||
|
||||
public class ReadService extends Service { |
||||
private static final String TAG = "ReadService"; |
||||
public static Boolean running = false; |
||||
public static final String ActionNewRead = "newRead"; |
||||
private Boolean speak = true; |
||||
private Boolean pause = false; |
||||
private List<String> contentList = new ArrayList<>(); |
||||
private int nowSpeak; |
||||
private int speechRate; |
||||
private String title; |
||||
private String text; |
||||
private int readAloudNumber; |
||||
private int progress; |
||||
private Boolean ttsInitSuccess = false; |
||||
private TextToSpeech textToSpeech; |
||||
private HashMap mParams; |
||||
|
||||
@Nullable |
||||
@Override |
||||
public IBinder onBind(Intent intent) { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public void onCreate() { |
||||
super.onCreate(); |
||||
} |
||||
|
||||
@Override |
||||
public int onStartCommand(Intent intent, int flags, int startId) { |
||||
if (intent != null) { |
||||
String action = intent.getAction(); |
||||
if (action != null) { |
||||
switch (action) { |
||||
case ActionNewRead: |
||||
newReadAloud(intent.getStringExtra("content"), |
||||
intent.getStringExtra("title"), |
||||
intent.getStringExtra("text"), |
||||
intent.getIntExtra("progress", 0)); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return super.onStartCommand(intent, flags, startId); |
||||
} |
||||
|
||||
|
||||
|
||||
@Override |
||||
public void onDestroy() { |
||||
super.onDestroy(); |
||||
} |
||||
|
||||
private void initTTS() { |
||||
if (textToSpeech == null) |
||||
textToSpeech = new TextToSpeech(this, status -> { |
||||
if (status == TextToSpeech.SUCCESS) { |
||||
textToSpeech.setLanguage(Locale.CHINA); |
||||
textToSpeech.setOnUtteranceProgressListener(new ttsUtteranceListener()); |
||||
ttsInitSuccess = true; |
||||
playTTS(); |
||||
} else { |
||||
ToastUtils.showError("TTS初始化失败!"); |
||||
ReadService.this.stopSelf(); |
||||
} |
||||
}); |
||||
if (mParams == null) { |
||||
mParams = new HashMap(); |
||||
mParams.put(TextToSpeech.Engine.KEY_PARAM_STREAM, "3"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 朗读监听 |
||||
*/ |
||||
private class ttsUtteranceListener extends UtteranceProgressListener { |
||||
|
||||
@Override |
||||
public void onStart(String s) { |
||||
//updateMediaSessionPlaybackState();
|
||||
//RxBus.get().post(RxBusTag.READ_ALOUD_START, readAloudNumber + 1);
|
||||
//RxBus.get().post(RxBusTag.READ_ALOUD_NUMBER, readAloudNumber + 1);
|
||||
} |
||||
|
||||
@Override |
||||
public void onDone(String s) { |
||||
readAloudNumber = readAloudNumber + contentList.get(nowSpeak).length() + 1; |
||||
nowSpeak = nowSpeak + 1; |
||||
if (nowSpeak >= contentList.size()) { |
||||
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.NEXT);
|
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onError(String s) { |
||||
//pauseReadAloud(true);
|
||||
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.PAUSE);
|
||||
} |
||||
|
||||
@Override |
||||
public void onRangeStart(String utteranceId, int start, int end, int frame) { |
||||
super.onRangeStart(utteranceId, start, end, frame); |
||||
//RxBus.get().post(RxBusTag.READ_ALOUD_NUMBER, readAloudNumber + start);
|
||||
} |
||||
} |
||||
/** |
||||
* 朗读 |
||||
*/ |
||||
public static void play(Context context, String content, String title, String text, int progress) { |
||||
Intent readAloudIntent = new Intent(context, ReadService.class); |
||||
readAloudIntent.setAction(ActionNewRead); |
||||
readAloudIntent.putExtra("content", content); |
||||
readAloudIntent.putExtra("title", title); |
||||
readAloudIntent.putExtra("text", text); |
||||
readAloudIntent.putExtra("progress", progress); |
||||
context.startService(readAloudIntent); |
||||
} |
||||
|
||||
private void newReadAloud(String content, String title, String text, int progress) { |
||||
if (TextUtils.isEmpty(content)) { |
||||
stopSelf(); |
||||
return; |
||||
} |
||||
this.text = text; |
||||
this.title = title; |
||||
this.progress = progress; |
||||
nowSpeak = 0; |
||||
readAloudNumber = 0; |
||||
contentList.clear(); |
||||
initTTS(); |
||||
String[] splitSpeech = content.split("\n"); |
||||
for (String aSplitSpeech : splitSpeech) { |
||||
if (!isEmpty(aSplitSpeech)) { |
||||
contentList.add(aSplitSpeech); |
||||
} |
||||
} |
||||
if (speak) { |
||||
speak = false; |
||||
pause = false; |
||||
playTTS(); |
||||
} |
||||
} |
||||
|
||||
private void playTTS() { |
||||
if (contentList.size() < 1) { |
||||
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.NEXT);
|
||||
return; |
||||
} |
||||
if (ttsInitSuccess && !speak) { |
||||
speak = !speak; |
||||
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.PLAY);
|
||||
//updateNotification();
|
||||
//initSpeechRate();
|
||||
HashMap<String, String> map = new HashMap<>(); |
||||
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "content"); |
||||
for (int i = nowSpeak; i < contentList.size(); i++) { |
||||
if (i == 0) { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, null, "content"); |
||||
} else { |
||||
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, map); |
||||
} |
||||
} else { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, null, "content"); |
||||
} else { |
||||
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, map); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
public enum Status { |
||||
PLAY, STOP, PAUSE, NEXT |
||||
} |
||||
} |
@ -0,0 +1,158 @@ |
||||
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.Collections; |
||||
|
||||
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.ReadCrawler; |
||||
|
||||
|
||||
public class HongChenReadCrawler implements ReadCrawler { |
||||
public static final String NAME_SPACE = "https://www.zuxs.net"; |
||||
public static final String NOVEL_SEARCH = "https://www.zuxs.net/search.php?key={key}"; |
||||
public static final String CHARSET = "gb2312"; |
||||
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("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 ""; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 从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.getElementById("listsss"); |
||||
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(readUrl + url); |
||||
chapters.add(chapter); |
||||
} |
||||
return chapters; |
||||
} |
||||
|
||||
/** |
||||
* 从搜索html中得到书列表 |
||||
* |
||||
* @param html |
||||
* @return |
||||
*/ |
||||
/* |
||||
<dl><dt><a href="/zu/1140.html" target="_blank"><img class="lazyimg" data-original="https://www.zuxs.net/files/article/image/0/29/29s.jpg"></a></dt> |
||||
<dd><a href="/zu/1140.html" class="bigpic-book-name" target="_blank"> |
||||
<font style="font-weight:bold;color:#f00">大主宰</font> |
||||
</a> |
||||
<p><a href="/author/%CC%EC%B2%CF%CD%C1%B6%B9.html" target="_blank">天蚕土豆</a> | <a href="/top/8_1.html" |
||||
target="_blank">其他类型</a> | 连载中</p> |
||||
<p class="big-book-info"> 大千世界,位面交汇,万族林立,群雄荟萃,一位位来自下位面的天之至尊,在这无尽世界,演绎着令人向往的传奇,追求着那主宰之路。 |
||||
无尽火域,炎帝执掌,万火焚苍穹。 |
||||
武境之内,武祖之威……</p> |
||||
<p><a href="/zu/1/1140/5284.html" target="_blank" class="red">最近更新 第1598章 邪神陨落(大结局)</a><span>| 09-06 |
||||
05:54更新</span></p> |
||||
</dd> |
||||
</dl> |
||||
*/ |
||||
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) { |
||||
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); |
||||
} |
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
return books; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,210 @@ |
||||
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.Collections; |
||||
import java.util.Comparator; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
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.ReadCrawler; |
||||
|
||||
|
||||
public class LaoYaoReadCrawler implements ReadCrawler { |
||||
public static final String NAME_SPACE = "https://www.laoyao.org"; |
||||
public static final String NOVEL_SEARCH = "https://www.laoyao.org/search.php?key={key}"; |
||||
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("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 ""; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 从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.getElementById("newlist"); |
||||
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(readUrl + url); |
||||
chapters.add(chapter); |
||||
} |
||||
return chapters; |
||||
} |
||||
|
||||
/** |
||||
* 从搜索html中得到书列表 |
||||
* |
||||
* @param html |
||||
* @return |
||||
*/ |
||||
/* |
||||
<li><a href="/info/6690.html" target="_blank" class="book_cov" title="大主宰"><img src="/public/images/default.jpg" |
||||
data-original="//www.laoyao.org/files/article/image/0/24/24s.jpg" class="lazyload_book_cover" alt="大主宰" /></a> |
||||
<div class="book_inf"> |
||||
<h3><a href="/info/6690.html" title="大主宰" target="_blank" mod="data_book_name"> |
||||
<font style="font-weight:bold;color:#f00">大主宰</font> |
||||
</a></h3> |
||||
<p class="tags"><span>作者:<a href="/creator/%E5%A4%A9%E8%9A%95%E5%9C%9F%E8%B1%86.html" title="天蚕土豆">天蚕土豆</a></span><span>分类:<a |
||||
href="/library/8_0_0_0_0_1.html" target="_blank">名著经典</a></span><span>状态:连载中</span><span>总字数:2498万字+</span></p> |
||||
<p><b>最近更新:</b><a href="/list/6690/21939.html" title="第1598章 邪神陨落(大结局)" target="_blank">第1598章 邪神陨落(大结局)</a></p> |
||||
<p class="int"> 大千世界,位面交汇,万族林立,群雄荟萃,一位位来自下位面的天之至尊,在这无尽世界,演绎着令人向往的传奇,追求着那主宰之路。 |
||||
无尽火域,炎帝执掌,万火焚苍穹。 |
||||
武境之内,武祖之威,震慑乾坤。 |
||||
西天之殿,百战之皇</p> |
||||
</div> |
||||
<div class="right"> |
||||
<span>更新时间:2020-09-06 06:47</span> |
||||
<a href="/info/6690.html" target="_blank" class="read_btn btn">立即阅读</a> |
||||
<a href="javascript:BookCaseAdd('6690');" class="store_btn btn" btn="book_fav">加入书架</a> |
||||
</div> |
||||
</li> |
||||
*/ |
||||
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) { |
||||
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>(); |
||||
Document doc = Jsoup.parse(html); |
||||
// try {
|
||||
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.getElementsByClass("result").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("int").first().text()); |
||||
book.setUpdateDate(li.getElementsByClass("right").first().getElementsByTag("span").text()); |
||||
String imgUrl = li.getElementsByTag("img").attr("data-original"); |
||||
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl); |
||||
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href").replace("info", "list").replace(".html", "/")); |
||||
book.setSource(BookSource.laoyao.toString()); |
||||
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor()); |
||||
books.add(sbb, book); |
||||
} |
||||
} |
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
return books; |
||||
} |
||||
|
||||
public Book getBookInfo(Document doc, Book book) { |
||||
//小说源
|
||||
book.setSource(BookSource.laoyao.toString()); |
||||
//图片url
|
||||
String imgUrl = doc.select("meta[property=og:image]").attr("content"); |
||||
book.setImgUrl(!imgUrl.contains("http") ? "https:" + imgUrl : imgUrl); |
||||
|
||||
//书名
|
||||
String title = doc.select("meta[property=og:novel:book_name]").attr("content"); |
||||
book.setName(title); |
||||
|
||||
//作者
|
||||
String author = doc.select("meta[property=og:novel:author]").attr("content"); |
||||
book.setAuthor(author); |
||||
|
||||
//更新时间
|
||||
String updateDate = doc.select("meta[property=og:novel:update_time]").attr("content"); |
||||
book.setUpdateDate(updateDate); |
||||
|
||||
//最新章节
|
||||
String newestChapterTitle = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content"); |
||||
book.setNewestChapterTitle(newestChapterTitle); |
||||
|
||||
//类型
|
||||
String type = doc.select("meta[property=og:novel:category]").attr("content"); |
||||
book.setType(type); |
||||
|
||||
//简介
|
||||
String desc = doc.select("meta[property=og:description]").attr("content"); |
||||
book.setDesc(desc); |
||||
return book; |
||||
|
||||
} |
||||
} |
@ -0,0 +1,204 @@ |
||||
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.Collections; |
||||
|
||||
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.ReadCrawler; |
||||
|
||||
|
||||
public class ShiGuangReadCrawler implements ReadCrawler { |
||||
public static final String NAME_SPACE = "https://www.youxs.org"; |
||||
public static final String NOVEL_SEARCH = "https://www.youxs.org/search.php?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 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("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 ""; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 从html中获取章节列表 |
||||
* |
||||
* @param html |
||||
* @return |
||||
*/ |
||||
public ArrayList<Chapter> getChaptersFromHtml(String html) { |
||||
ArrayList<Chapter> chapters = new ArrayList<>(); |
||||
Document doc = Jsoup.parse(html); |
||||
Element divList = doc.getElementById("listsss"); |
||||
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 |
||||
*/ |
||||
/* |
||||
<li><a href="/wuxian/4/4473/" target="_blank" class="book_cov" title="大主宰"><img src="/public/images/default.jpg" |
||||
data-original="https://www.youxs.org/files/article/image/0/29/29s.jpg" class="lazyload_book_cover" alt="大主宰" /></a> |
||||
<div class="book_inf"> |
||||
<h3><a href="/wuxian/4/4473/" title="大主宰" target="_blank" mod="data_book_name"> |
||||
<font style="font-weight:bold;color:#f00">大主宰</font> |
||||
</a></h3> |
||||
<p class="tags"><span>作者:<a title="天蚕土豆">天蚕土豆</a></span><span>分类:<a href="/liebiao/8_0_0_0_0_1.html" target="_blank">网络文学</a></span><span>状态:连载中</span><span>总字数:2497万字+</span></p> |
||||
<p><b>最近更新:</b><a href="/wuxian/4/4473/15283.html" title="第1598章 邪神陨落(大结局)" target="_blank">第1598章 邪神陨落(大结局)</a></p> |
||||
<p class="int"> 大千世界,位面交汇,万族林立,群雄荟萃,一位位来自下位面的天之至尊,在这无尽世界,演绎着令人向往的传奇,追求着那主宰之路。 |
||||
无尽火域,炎帝执掌,万火焚苍穹。 |
||||
武境之内,武祖之威</p> |
||||
</div> |
||||
<div class="right"> |
||||
<span>更新时间:09-06 05:25</span> |
||||
<a href="/wuxian/4/4473/" target="_blank" class="read_btn btn">立即阅读</a> |
||||
<a href="javascript:BookCaseAdd('4473');" class="store_btn btn" btn="book_fav">加入书架</a> |
||||
</div> |
||||
</li> |
||||
*/ |
||||
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) { |
||||
ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>(); |
||||
Document doc = Jsoup.parse(html); |
||||
// try {
|
||||
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.getElementsByClass("result").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("int").first().text()); |
||||
book.setUpdateDate(li.getElementsByClass("right").first().getElementsByTag("span").text()); |
||||
String imgUrl = li.getElementsByTag("img").attr("data-original"); |
||||
book.setImgUrl(imgUrl); |
||||
book.setChapterUrl(NAME_SPACE + as.get(1).attr("href")); |
||||
book.setSource(BookSource.shiguang.toString()); |
||||
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor()); |
||||
books.add(sbb, book); |
||||
} |
||||
} |
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
return books; |
||||
} |
||||
|
||||
public Book getBookInfo(Document doc, Book book) { |
||||
//小说源
|
||||
book.setSource(BookSource.shiguang.toString()); |
||||
//图片url
|
||||
String imgUrl = doc.select("meta[property=og:image]").attr("content"); |
||||
book.setImgUrl(imgUrl); |
||||
|
||||
//书名
|
||||
String title = doc.select("meta[property=og:novel:book_name]").attr("content"); |
||||
book.setName(title); |
||||
|
||||
//作者
|
||||
String author = doc.select("meta[property=og:novel:author]").attr("content"); |
||||
book.setAuthor(author); |
||||
|
||||
//更新时间
|
||||
String updateDate = doc.select("meta[property=og:novel:update_time]").attr("content"); |
||||
book.setUpdateDate(updateDate); |
||||
|
||||
//最新章节
|
||||
String newestChapterTitle = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content"); |
||||
book.setNewestChapterTitle(newestChapterTitle); |
||||
|
||||
//类型
|
||||
String type = doc.select("meta[property=og:novel:category]").attr("content"); |
||||
book.setType(type); |
||||
|
||||
//简介
|
||||
String desc = doc.select("meta[property=og:description]").attr("content"); |
||||
book.setDesc(desc); |
||||
return book; |
||||
|
||||
} |
||||
} |
@ -0,0 +1,166 @@ |
||||
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.Collections; |
||||
|
||||
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.ReadCrawler; |
||||
|
||||
|
||||
public class XiaGuReadCrawler implements ReadCrawler { |
||||
public static final String NAME_SPACE = "https://www.xiagu.org"; |
||||
public static final String NOVEL_SEARCH = "https://www.xiagu.org/search/?keyword={key}&t=0"; |
||||
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("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 ""; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 从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.getElementById("listsss"); |
||||
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(readUrl + url); |
||||
chapters.add(chapter); |
||||
} |
||||
return chapters; |
||||
} |
||||
|
||||
/** |
||||
* 从搜索html中得到书列表 |
||||
* |
||||
* @param html |
||||
* @return |
||||
*/ |
||||
/* |
||||
<li class="subject-item"> |
||||
<div class="pic"> |
||||
<a class="nbg" href="/xs/5584.html" ><img class="" data-original="//www.xiagu.org/files/article/image/0/29/29s.jpg" src="/statics/images/default.jpg" width="90"></a> |
||||
</div> |
||||
<div class="info"> |
||||
<h2 class=""><a href="/xs/5584.html"><font style="font-weight:bold;color:#f00">大主宰</font></a></h2> |
||||
<div class="pub">作者:<a target="_blank" href="/author/id/186.html">天蚕土豆</a> / 类型:<a target="_blank" href="/shuku/8_0_0_0_0_1.html">其他类型</a> / 2020-09-06 / 连载中 / 2497.0808万字</div> |
||||
|
||||
<p>【内容简介】 大千世界,位面交汇,万族林立,群雄荟萃,一位位来自下位面的天之至尊,在这无尽世界,演绎着令人向往的传奇,追求着那主宰之路。<br /> |
||||
无尽火域,炎帝执掌,万火焚苍穹。<br /> |
||||
武境之内,武祖之威... </p> |
||||
<div class="ft"> |
||||
|
||||
<div class="pub">角色:牧尘,唐芊儿,红绫,牧哥,苏凌,刘彻,柳阳,牧锋,芊儿,柳慕白,薛东,童哥,柳眉,唐芊儿蹙,姬玄,牧哥比,那柳阳,乐乐,凌撇,杨柳,林修,牧尘沉,莫师,代柳阳</div> |
||||
<div class="cart-actions"> |
||||
<span class="market-info"><a href="/read/5/5584/" target="_blank">【最新章节】第1598章 邪神陨落(大结局)</a></span> |
||||
</div> |
||||
<div class="ebook-link"><a target="_blank" href="/xs/5584.html">详细介绍</a></div> |
||||
</div> |
||||
</div> |
||||
</li> |
||||
*/ |
||||
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) { |
||||
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); |
||||
} |
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
return books; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,158 @@ |
||||
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.Collections; |
||||
|
||||
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.ReadCrawler; |
||||
|
||||
|
||||
public class XingXingReadCrawler implements ReadCrawler { |
||||
public static final String NAME_SPACE = "https://www.hs918.com"; |
||||
public static final String NOVEL_SEARCH = "https://www.hs918.com/search.php?key={key}"; |
||||
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("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 ""; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 从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.getElementById("newlist"); |
||||
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(readUrl + url); |
||||
chapters.add(chapter); |
||||
} |
||||
return chapters; |
||||
} |
||||
|
||||
/** |
||||
* 从搜索html中得到书列表 |
||||
* |
||||
* @param html |
||||
* @return |
||||
*/ |
||||
/* |
||||
<li> |
||||
<div class="sCboxBookParL left"><a href="/xiaoshuo/21351.html"><img data-original="https://www.hs918.com/files/article/image/20/20240/20240s.jpg" /></a></div> |
||||
<div class="sCboxBookParR left"> |
||||
<div class="top clearfix"> |
||||
<h1><a href="/xiaoshuo/21351.html"><font style="font-weight:bold;color:#f00">大主宰</font>之剑仙</a></h1> |
||||
<span class="s2">遗弃的梦 </span> |
||||
<span class="s4">95万字</span> |
||||
<span class="s6">474人气值</span> |
||||
</div> |
||||
<div class="tips clearfix"><a href="/fenlei/3_0_0_0_0_1.html" title="浪漫青春" class="tipsa">浪漫青春</a></div> |
||||
<div class="c"><strong>内容介绍:</strong> 一位少年意外穿越大主宰,结识了牧尘…………(新人作家,写得不好还请多多包涵) |
||||
...</div> |
||||
<div class="bottom clearfix"> |
||||
<span class="redTps">最近更新</span> |
||||
<a href="/xiaoshuo/21351/43873.html">第57章:陷阱</a> |
||||
|
||||
<span class="time2">更新时间:2020-12-05 01:45</span> |
||||
</div> |
||||
</div> |
||||
<div class="sCboxBookParS right"> |
||||
<a href="/xiaoshuo/21351/" class="b1">开始阅读</a> |
||||
<a href="javascript:;" onclick="BookCaseAdd('21351');" class="b2 apdBshelf">加入书架</a> |
||||
</div> |
||||
</li> |
||||
*/ |
||||
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) { |
||||
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); |
||||
} |
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
return books; |
||||
} |
||||
|
||||
|
||||
} |
@ -1,2 +1,2 @@ |
||||
#Mon Nov 30 10:23:34 CST 2020 |
||||
VERSION_CODE=174 |
||||
#Sun Dec 06 12:06:58 CST 2020 |
||||
VERSION_CODE=175 |
||||
|
Loading…
Reference in new issue