第一次爬虫笔记
培训
学习到了简单爬虫程序:
线上的时候没有很多时间来细细读代码,一遍过去只能说是懵的.
但是多跟几遍录屏,搜索了很多资料和动手实践后对代码的理解越来越多.
学习过程
规范用户输入url
可能不小心没审到要换个网站的句子,我首先把学长的代码跟着录屏复制下来,
然后考虑用户输入的规范性.
考虑过自动补全或修正用户输入的url的想法,查了资料...没能实现
这个class在IDEA里并没有报错...但也运行不起来
public class GetProtocol {
private final static String HTTP= "http://";
private final static String HTTPS = "https://";
private String newurl;
//判断协议 能连接上则协议正确
public String getProtocol(String url) {
newurl = clearUrl(url);
url = HTTP + newurl;
if (exists(url)) {
return url;
} else {
url = HTTPS + newurl;
if (exists(url)) {
return url;
} else {
return null;
}
}
}
//清除URL里多余的符号
private String clearUrl(String url) {
if (url.contains(HTTP)) {
url = url.substring(url.lastIndexOf(HTTP) + HTTP.length());
for (int i = 0; i < url.length(); i++) {
if (url.charAt(i) == '/' || url.charAt(i) == '.'
|| url.charAt(i) == '\\') {
} else {
url = url.substring(i);
return url;
}
}
} else if (url.contains(HTTPS)) {
url = url.substring(url.lastIndexOf(HTTPS) + HTTPS.length());
for (int i = 0; i < url.length(); i++) {
if (url.charAt(i) == '/' || url.charAt(i) == '.'
|| url.charAt(i) == '\\') {
} else {
url = url.substring(i);
return url;
}
}
}else{
for (int i = 0; i < url.length(); i++) {
if (url.charAt(i) == '/' || url.charAt(i) == '.'
|| url.charAt(i) == '\\') {
} else {
url = url.substring(i);
return url;
}
}
}
return url;
}
//是否能连接上
private boolean exists(String url) {
try {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setConnectTimeout(3000);
return (con.getResponseCode() == 200);
} catch (Exception e) {
return false;
}
}
}
emmmm所以最后采用文明用语.温馨提示
System.out.println("请输入https://www.xbiquge.so/(笔趣阁)中的小说目录网址");//此时还没换网站
System.out.println("否则无法运行:");//天真的我此时还不知道为什么不能运行(T^T)
接着加上作者名,目录名
作者名好办,直接模仿,刚好是第一个p标签
String author = document.body().selectFirst("p").text();
目录名就...//此处省略一千字痛苦过程
这里查阅资料了解了一些select的用法(中途还有一些find,但是我并没有用到)
-
标签名查找
Elements as = menu.select("a[href]");//这里还带了属性 Elements menu = document.body().select("dl dd")//可以用多个一起
-
id名来查找
Elements elements = document.select("#conten");
-
class名查找
Elements elements = document.select(".box_con");//尝试过,但是出现好多杂乱的信息,感觉不太美观
还有一些根据文本内容,和正则表达式一起运用等等.
最终采用了Elements elements = document.select("#list");
然后琢磨怎么才能跳过最新章节...由于dt和dd在小说html里我看着不是父子元素,我也不清楚如何跳过去,删除,或设置内容查重来达到
除去最新章节的效果(这些相关资料都查了,但真的真的还是没找到解决办法,很无奈...)
查询过程中了解了索引index一些知识,问题是这本小说在96之后是正文章节,不一定其他的是...
开始对文本内容琢磨
首先把文本内容变成字符串待处理
Element chapterContent = chapter.selectFirst("#content");
String content = chapterContent.text();//尽管我不清楚会不会占太多空间
然后思考怎么分段落,这内容一出来就是一条线...(此处再次省略一千次的痛苦查询过程)
尽管我已经知道是因为\
与\r\n转换的问题
有一些解决方案比如:用模拟浏览器的方法抓取网页,先进行页面处理替换再替换回来,于是兴冲冲去搜索下一秒就哭了,能写简单爬虫也是因为有一个模板,而且我也不知道怎么先进行页面处理.
于是我只能考虑把"。"换成"。+\n"
一开始只找到了replaceAll方法,并没有意识到这个一定要用正则匹配(给我狠狠学)
开始大量试错,期间找到了中文标点符号对应(这里找到一个转码小软件)
- 。:\u3002
- ;:\uff1b
- ,:\uff0c
- ::\uff1a
- “ ”:\u201c\u201d
- ():\uff08\uff09
- 、:\u3001
- ?:\uff1f
- 《》:\u300a\u300b
但是说实话,这里的"。"表达要用"\u3002",我还是更喜欢用replace直接换
String content1 = content.replaceAll("\u3002","\u3002\n\n");
fileOut.write(("\n\n" + "## " + chapterName + "\n\n " + content1).getBytes());
}
顺便把目录也顺顺//尽管我后面觉得有了二级标题就不需要目录页了...
String cata1 = cata.replace("第","\n第");//原本打算用markdown表格的,但...一言难尽
加入一级和二级标题
String title1 = "# " + title + " ";
String cata1 = cata.replace("第","\n第");
fileOut.write((title1+"\n\n" + author + "\n\n" + cata1 ).getBytes());
fileOut.write(("\n\n" + "## " + chapterName + "\n\n " + content1).getBytes());
终于发现要改网站了
刚开始我并没有意识到事情的严重性
单纯把url换了下
String menuUrl = "https://www.aixiaxsw.com/100/100677/";//默认目录页
开始不断运行,不断报错...//以后一定要重视报错里的提示,可以先变成中文看看大意
刚开始排查错误找的也只是menuurl
后面才看到是因为这个网站的menuurl+sublink合并起来重了...天呐
try {
chapter = Jsoup.connect(menuUrl+subLink).timeout(10000).get();
} catch (IOException ewww) {
ewww.printStackTrace();
}
然后很快就改好了
try {
String url2 = "https://www.aixiaxsw.com/";
chapter = Jsoup.connect(url2+subLink).timeout(10000).get();
} catch (IOException ewww) {
ewww.printStackTrace();
}
虽然已经打了jar包了,但是不清楚代码是否要复制在这里...
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.*;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class spider {
public static void main(String[] args) throws IOException {
String menuUrl = "https://www.aixiaxsw.com/100/100677/";//默认目录页
final String fileAddr = "./";
Scanner scanner = new Scanner(System.in);
System.out.println("输入1则根据下次输入的目录爬取,输入2则爬取示例小说《我在冥界当萌新》");
if(scanner.nextInt()==1) {
System.out.println("请输入https://www.aixiaxsw.com/(爱下书小说网)中的小说目录网址");
System.out.println("否则无法运行:");
menuUrl = scanner.next();
}
//这个部分是标题,作者,目录
Document document = null;//新建一个文档
try {
document = Jsoup.connect(menuUrl).get();
} catch (IOException ewww) {
ewww.printStackTrace();
}
String title = document.body().selectFirst("h1").text();
String author = document.body().selectFirst("p").text();
Elements catalogue = document.body().select("#list");
String cata = catalogue.text();
System.out.println("开始爬取:"+title);
Elements menu = document.body().select("dl dd");//选择父元素为dl的所有dd标签
Elements as = menu.select("a[href]");
System.out.println("小说将保存在:"+fileAddr + title+".md 中");
File file = new File(fileAddr + title+".md");
OutputStream fileOut = null;
try {
fileOut = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String title1 = "# " + title + " ";
String cata1 = cata.replace("第","\n第");
fileOut.write((title1+"\n\n" + author + "\n\n" + cata1 ).getBytes());
int count = 1;
//循环操作每个章节
for (Element a : as){
if(count<=12){
count++;
continue;
}
String subLink = a.attr("href");
String chapterName = a.text();
System.out.println("当前爬取章节:"+chapterName);
Document chapter = null;
try {
String url2 = "https://www.aixiaxsw.com/";
chapter = Jsoup.connect(url2+subLink).timeout(10000).get();
} catch (IOException ewww) {
ewww.printStackTrace();
}
Element chapterContent = chapter.selectFirst("#content");
String content = chapterContent.text();
String content1 = content.replaceAll("\u3002","\u3002\n\n");
fileOut.write(("\n\n" + "## " + chapterName + "\n\n " + content1).getBytes());
}
System.out.println("小说爬取完成");
fileOut.close();
}
}
体会
很巧,第一节IDEA实验课助教没来,我参加了这周四的java讲座(两大总监都在,可惜在108...(T^T))
听了好多学姐学长的经验分享,学习分享,会有一种很奇妙的感觉.很庆幸当初勇敢地去了学线的面试,然后收获了敲代码的快乐.
尽管我知道这代码迟早要敲,但是在IDEA实验课上看到大部分同学生疏的新建文件,犹豫着敲下main方法的时候,在听到学长强调一定要多敲代码的时候,会很感激培训时懵逼地敲下一串东西,慢慢有了更深的理解,在运行成功时的那种开心.
因为培训的内容和作业让我不得不去搜索知识,学习一些java知识.(作业让我又爱又恨就是了!!!)
在java课学习过程中,才发现那些知识让我能更容易去理解老师新课的内容,更快地接受
//就是一些听了讲座很奇妙的体会