学习一个——苟
1. 开发目的
- 拜读了某神犇的blog,感到了自身深深的不足。蒟蒻如我,决定提高一蛤自身的姿势水平,学习一个,使用Java重写用GreatestLanguage写的某小说网站的抓取器。
2. 分析&实现
2.1 Gui
- 因为有之前帮国外小老板写java作业的经验:
- 他object的PDF上实现效果是这样:
- 我实现的弱鸡效果是这样:
- 使用GridLayout实现的代码:
guiFrame =new JFrame("龙弟弟");
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setLocation(400, 200);
JPanel panel=new JPanel(new GridLayout(0,8));
for(int i=0;i<64;++i) {
Color tmp=new Color((int)(1+Math.random()*255),(int)(1+Math.random()*255),(int)(1+Math.random()*255));
arrayLabels[i]=new ColorLabel(40,40,tmp);
panel.add(arrayLabels[i]);
}
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
guiFrame.setLayout(gridbag);
c.weightx = 1.0;
c.weighty = 1.0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = 1;
gridbag.setConstraints(panel, c);
guiFrame.add(panel);
JButton b = new JButton("Press me to refresh labels");
Dimension preferredSize = new Dimension(320,40);
b.setPreferredSize(preferredSize);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
for(int i=0;i<64;++i) {
Color tmp=new Color((int)(1+Math.random()*255),(int)(1+Math.random()*255),(int)(1+Math.random()*255));
arrayLabels[i].SetDrawColor(tmp);
}
guiFrame.setTitle("LDD");
guiFrame.repaint();
}
});
guiFrame.add(b);
guiFrame.setVisible(true);
guiFrame.setSize(guiFrame.getPreferredSize());
+ emmm这也算是用GridLayout完成了
- 所以这次我熟练了!GridLayout垃圾!EmptyBorder最高!
- 我设想的是这样:
- 最后做出来是这样:
- Code:
public Gui() {
setTitle("苟");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(350,400);
Font f = new Font("微软雅黑", Font.BOLD, 18);
UIManager uiManager=new UIManager();
uiManager.put("Label.font", f);
uiManager.put("TextField.font", f);
uiManager.put("TextField.setColumns", 1);
uiManager.put("TextArea.font", f);
uiManager.put("Button.font", f);
uiManager.put("RadioButton.font", f);
JPanel content;
content = new JPanel();
content.setBackground(SystemColor.controlHighlight);
content.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(content);
content.setLayout(null);
JLabel label1=new JLabel("网址:");
label1.setBounds(15, 10, 100, 30);
content.add(label1);
JTextField textField1 = new JTextField();
textField1.setColumns(1);
textField1.setBounds(115, 10, 180, 30);
content.add(textField1);
JLabel label2=new JLabel("保存地址:");
label2.setBounds(15, 45, 100, 30);
content.add(label2);
JTextField textField2 = new JTextField("E://");
textField2.setBounds(115, 45, 180, 30);
content.add(textField2);
JLabel label3=new JLabel("线程数:");
label3.setBounds(15, 80, 100, 30);
content.add(label3);
JTextField textField3 = new JTextField("20");
textField3.setBounds(115, 80, 30, 30);
content.add(textField3);
textField3.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
int keyChar = e.getKeyChar();
if(keyChar >= KeyEvent.VK_0 && keyChar <= KeyEvent.VK_9){
}else{
e.consume();
}
}
});
JLabel label4=new JLabel("检查间隔/s:");
label4.setBounds(150, 80, 130, 30);
content.add(label4);
JTextField textField4 = new JTextField("1");
textField4.setBounds(265, 80, 30, 30);
content.add(textField4);
JLabel label5=new JLabel("过滤规则:");
label5.setBounds(15, 115, 130, 30);
content.add(label5);
JTextArea textArea1 = new JTextArea();
JScrollPane scrollPane=new JScrollPane(textArea1);
scrollPane.setBounds(15, 150, 120, 180);
scrollPane.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
content.add(scrollPane);
JRadioButton radiobutton1=new JRadioButton("完成时打开",true);
radiobutton1.setBounds(160, 115, 130, 30);
content.add(radiobutton1);
JTextArea textArea2 = new JTextArea();
textArea2.setBounds(160, 150, 130, 130);
content.add(textArea2);
JButton button1 = new JButton("Do it!");
button1.setBounds(160, 300, 130, 30);
button1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(Gui.this,"开始抓取!");
}
});
content.add(button1);
}
+ 所以Java跟GreatestLanguage对像素的定义居然不一样???
+ 抄(划)用到的姿势:
* [文本框添加滚动条](https://blog.csdn.net/xueerfei008/article/details/36006961)
* [批量设置控件属性](https://blog.csdn.net/yjqyyjw/article/details/52301963)
* [文本框只允许输入数字](https://blog.csdn.net/lanjianhun/article/details/8273453)
+ 未实现的:
* 文本框加上调节器,Java似乎没有这个控件,需要手动实现
2.2 HTTP读文本&正则取出文本中间内容
- Java没有封装HTTP读文本类肿么办!不怕!抄(划掉)学习一个!不会正则肿么办,emmmmm,只有学习一个了。
- 一开始抄的HTTP读文本蜜汁不支持读网页端的笔趣阁,只能读wap端口的
- wap端口的目录一个网页只有20章
- 要翻页获取
- 每次下一页所在的标签都不是用一个位置
- 第一页和最后一页要特殊定义
- 然后我都实现了!
String bookurl="http://m.b5200.net"+UrlList.get(2);
List<String> allurl = new ArrayList();
List<String> allna = new ArrayList();
List<String> NameList;
//获取正序目录
content = getHtmlContent(bookurl);
regex = "<a[^>]*href="/wapbook-[^>]*>.*?</a>";
link = getContentByRegex(content,regex);
UrlList = match(link.toString(), "a", "href");
bookurl="http://m.b5200.net"+UrlList.get(0);
String endurl="http://m.b5200.net"+UrlList.get(2);
//访问正序目录
//boolean first=true;
/*while(bookurl!=endurl) {
System.out.println(bookurl);
content = getHtmlContent(bookurl);
regex = "<a[^>]*href="/wapbook-[^>]*>.*?</a>";
link = getContentByRegex(content,regex);
UrlList = match(link.toString(), "a", "href");
//System.out.println(UrlList);
if(first){first=false;bookurl="http://m.b5200.net"+UrlList.get(2);}
else {bookurl="http://m.b5200.net"+UrlList.get(4);}
regex = "<a[^>]*href='/wapbook-[^>]*>.*?</a>";
link = getContentByRegex(content,regex);
UrlList = match(link.toString(), "a", "href");
NameList = getLabelValues(link.toString(),regex);
allurl.addAll(UrlList);
allna.addAll(NameList);
+ 最后发现wap端容易崩,单线程读5次目录就502了……Orz,只能重写
public static List<Map<String, String>> getbook(String urlNameString) {
List<Map<String, String>> reqMap = new ArrayList<Map<String, String>>();
try {
String content = getHtmlContent(urlNameString);
System.out.println(getTitle(content));
// 获取小说信息的结果
String regex = "<a[^>]*href="" + urlNameString + "[^>]*>.*?</a>";
List<String> link = getContentByRegex(content, regex);// 包含标签的地址
List<String> UrlList = match(link.toString(), "a", "href"); // 每章Url地址
List<String> NameList = getLabelValues(link.toString(), regex); // 每章标题
//System.out.println("NameList:" + NameList.get(0));
//getchapter(UrlList.get(0));
} catch (Exception e) {
e.printStackTrace();
}
return reqMap;
}
private static String getchapter(String Url) {
StringBuilder chapter = new StringBuilder();
try {
String content = getHtmlContent(Url);
String regex = "<div id="content">[^>]*>.*?</div>";
List<String> tmp = getContentByRegex(content, regex);
List<String> tmp2 = getLabelValues(tmp.toString(), regex);
String tmp3 = tmp2.get(0);
System.out.println(tmp3);
String[] array = tmp3.split(" ");
for (String str : array) {
chapter.append(str).append("
");
}
// System.out.println(chapter.toString());
} catch (Exception e) {
e.printStackTrace();
}
return chapter.toString();
}
+ 美丽的测试输出:
2.3 天国的多线程
- 由于我太弱,研究一晚上仍未找到跨类调用的方法,比如说在Thread类中调用GUI类中定义的Re类中的某个项-、-
- 还比如如何在Thread类中修改GUI类中定义的JFrame中的参数,比如说
Thread extends Gui{
……
super.setTitle();
super.TextArea1.setFront();
- 都是不合法的…战略性放弃,改日再战。
- 本来写的检查间隔是用来设置一个clock来监控操作是否完成强行结束线程防止溢出的,现在成了摆设=、=
- 还是易语言写多线程&图形化编程简单啊…
2.4 获取章节内容并输出
FileWriter fw = new FileWriter(SaveAddress, true);
BufferedWriter bw = new BufferedWriter(fw);
bw.append(getTitle()+"
");
for(int i=0;i<a.num;++i) {
bw.append(a.NameList.get(i)+"
");
textArea2.append(a.NameList.get(i)+"
");
bw.append(a.getchapter(i));
System.out.println(a.NameList.get(i));
Thread.currentThread().sleep(1000);
}
bw.close();
fw.close();
- 最终效果:,也算是基本实现了功能
2.5 完成时打开文件夹
- 似乎有
runtime.exec("explorer /select, " + yourFileOrFolderLocation);
这种神奇的操作,但我没有实现。
- code:
if(radiobutton1.isSelected())
try {
java.awt.Desktop.getDesktop().open(new File(SaveAddress));
} catch (IOException e2) {
e2.printStackTrace();
}
3. 后记
- 也算是Java写的第一个具有一定应用价值的桌面化程序,已发布在Github。
- 代码书写格式仍有许多不足,大抵是平时练习过少导致的,也有少部分是因为OI带来的历史遗留问题,只考虑完成算法-》完美运行,没有考虑到后续维护。
- 懒,没写纯字符串的文本_取出中间文本,文本_去中间_批量,大概会比正则快上那么一点?主要是Java调用不了易语言写的DLL,太遗憾了。
- 最后跟我念:”E is the Greatest Language!"