之前有看过一段时间爬虫,了解了爬虫的原理,以及一些实现的方法,本项目完成于半年前,一直放在那里,现在和大家分享出来。

网络爬虫简单的原理就是把程序想象成为一个小虫子,一旦进去了一个大门,这个小虫子就像进入了新世界一样,只要符合他的口味的东西就会放在自己的袋子里,但是他还不满足,只要见到可以打开的门,他都要进去看看,里面有没有他想要的东西有就装起来,直到每个门里都看了一遍,确定没有了之后,他才肯放弃,这样下来,他的袋子已经装满了想要的东西。

上述内容表述起来就是:网络爬虫就是一个自动提取网页内容的程序,这个程序的行为像一个虫子似的,爬来爬去。一般的网络爬虫都有一个或者多个网页的url作为开始,从开始的网页上获取url,并把符合条件的内容保存下来,这样一直进行下去,直到条件不符合的时候,程序执行结束。

以下只是简单的一个爬虫,爬取一个下载网站上的迅雷下载链接,用到了两个辅助队列,一个存链接作为判断当前链接是否已经打开过,另一个是进行操作的队列,存进去的链接都会进行操作。最后获取到的下载链接存在set集合中,以保证链接不会重复。

-------------------------------以下是一个分析源码的过程,后期发现这个编码没有用上---------------------------------------------------------------------

由于在网页上显示的只是一串文字,当用户点击后,他的链接会经过url编码,编码成迅雷能够识别的链接,网站上使用的是javascript的url编码,java自带了一个url编码,和网站上的不一致,我们需要java的url编码的源码,通过分析源码其实很难简单地发现对什么字符编码,对什么不进行编码,和javascript的url编码比较之后,对其进行改造,经过比对,发现java的编码,对'@','[',']',':','/'不处理,只需要增加他们进去就行

static {

    dontNeedEncoding = new BitSet(256);
int i;
for (i = 'a'; i <= 'z'; i++) {
dontNeedEncoding.set(i);
}
for (i = 'A'; i <= 'Z'; i++) {
dontNeedEncoding.set(i);
}
for (i = '0'; i <= '9'; i++) {
dontNeedEncoding.set(i);
}
dontNeedEncoding.set(' '); /* encoding a space to a + is done
* in the encode() method */
dontNeedEncoding.set('-');
dontNeedEncoding.set('_');
dontNeedEncoding.set('.');
dontNeedEncoding.set('*'); dfltEncName = AccessController.doPrivileged(
new GetPropertyAction("file.encoding")
);
}

改造后的url编码类,去掉了没有用的语句,增加对对'@','[',']',':','/'特殊字符的编码

package url;

import java.io.UnsupportedEncodingException;
import java.io.CharArrayWriter;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.BitSet; public class URLEncoders {
static BitSet dontNeedEncoding;
static final int caseDiff = ('a' - 'A');
static String dfltEncName = null; static {
dontNeedEncoding = new BitSet(256);
int i;
for (i = 'a'; i <= 'z'; i++) {
dontNeedEncoding.set(i);
}
for (i = 'A'; i <= 'Z'; i++) {
dontNeedEncoding.set(i);
}
for (i = '0'; i <= '9'; i++) {
dontNeedEncoding.set(i);
}
dontNeedEncoding.set(' '); /*
* encoding a space to a + is done in the
* encode() method
*/
dontNeedEncoding.set('-');
dontNeedEncoding.set('_');
dontNeedEncoding.set('.');
dontNeedEncoding.set('*');
dontNeedEncoding.set('@');
dontNeedEncoding.set('[');
dontNeedEncoding.set(']');
dontNeedEncoding.set(':');
dontNeedEncoding.set('/'); } @Deprecated
public static String encode(String s) { String str = null; try {
str = encode(s, dfltEncName);
} catch (UnsupportedEncodingException e) {
} return str;
} public static String encode(String s, String enc)
throws UnsupportedEncodingException { boolean needToChange = false;
StringBuffer out = new StringBuffer(s.length());
Charset charset;
CharArrayWriter charArrayWriter = new CharArrayWriter(); if (enc == null)
throw new NullPointerException("charsetName"); try {
charset = Charset.forName(enc);
} catch (IllegalCharsetNameException e) {
throw new UnsupportedEncodingException(enc);
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
} for (int i = 0; i < s.length();) {
int c = (int) s.charAt(i);
if (dontNeedEncoding.get(c)) {
if (c == ' ') {
c = '+';
needToChange = true;
}
out.append((char) c);
i++;
} else {
do {
charArrayWriter.write(c); if (c >= 0xD800 && c <= 0xDBFF) { if ((i + 1) < s.length()) {
int d = (int) s.charAt(i + 1);
if (d >= 0xDC00 && d <= 0xDFFF) {
charArrayWriter.write(d);
i++;
}
}
}
i++;
} while (i < s.length()
&& !dontNeedEncoding.get((c = (int) s.charAt(i)))); charArrayWriter.flush();
String str = new String(charArrayWriter.toCharArray());
byte[] ba = str.getBytes(charset);
for (int j = 0; j < ba.length; j++) {
out.append('%');
char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
if (Character.isLetter(ch)) {
ch -= caseDiff;
}
out.append(ch);
ch = Character.forDigit(ba[j] & 0xF, 16);
if (Character.isLetter(ch)) {
ch -= caseDiff;
}
out.append(ch);
}
charArrayWriter.reset();
needToChange = true;
}
} return (needToChange ? out.toString() : s);
}
}

所以当我研究好了以上的编码之后才发现,迅雷会识别未经过编码的链接,三种链接迅雷都可以下载,如下图:

所以以上就当是提高了一下分析源码的能力……

爬虫代码并没有做任何的优化,可以说效率非常低,程序用到了递归,并且在程序运行的过程中打开的链接会形成一个环形,也就是打开一个链接,之后程序执行的过程中会再次找到这个链接,所以这条路线就断了。

程序在执行过程中,如果当前访问的网址时间过长,会抛出异常,也会影响效率。

从运行时间和有效链接可以看出效率很低

其实爬虫的代码很简单,从网页获取代码,对其进行解析这么一个过程

主程序:并没有调用其他的方法,那个编码类也没有用上

package function;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import queue.Queue; import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern; public class Crawler {
public static Queue q1 = new Queue();
public static Queue q2 = new Queue();
public static Set<String> set = new TreeSet<String>();
public static int i = 0; public static void main(String[] args) {
Document doc = null;
try {
long begin = System.currentTimeMillis();
doc = Jsoup.connect("http://www.dytt8.net/index.htm").get();
Elements links = doc.select("a[href]");
for (Element link : links) {
String linkHref = link.attr("href");
Pattern pattern = Pattern.compile("^/html/+(.)+.html");
Pattern pattern0 = Pattern
.compile("http://www.dytt8.net/html/+(.)+.html");
Pattern pattern1 = Pattern.compile("^ftp://+((.)+)+");
if (pattern.matcher(linkHref).matches() == true
|| pattern0.matcher(linkHref).matches() == true) {
q1.insertQueue(linkHref);
q2.insertQueue(linkHref);
open("http://www.dytt8.net" + q1.outQueue());
}
}
Iterator<String> it = set.iterator();
// while(it.hasNext()){
// String url=(String)it.next();
// int last=url.lastIndexOf(".");
// int last1=url.lastIndexOf("]");
// // System.out.print(url.substring(last1+1, last)+" ");
// System.out.println(URLEncoders.encode(url,"utf-8"));
// }
System.out.println("一共爬取" + q2.size() + "条链接");
long end = System.currentTimeMillis();
System.out.println("用时" + (end - begin) + "ms");
System.out.println("一共" + set.size() + "条下载链接");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public static void open(String url) {
Document doc = null;
try {
doc = Jsoup.connect(url).get();
Elements links = doc.select("a[href]");
for (Element link : links) {
String linkHref = link.attr("href");
Pattern pattern = Pattern.compile("^/html/+(.)+.html");
Pattern pattern0 = Pattern
.compile("http://www.dytt8.net/html/+(.)+.html");
Pattern pattern1 = Pattern.compile("^ftp://+((.)+)+");
if (pattern.matcher(linkHref).matches() == true
|| pattern0.matcher(linkHref).matches() == true) {
q1.insertQueue(linkHref);
q2.insertQueue(linkHref);
if (q2.contains(linkHref) == false) {
open("http://www.dytt8.net" + q1.outQueue());
}
} else if (pattern1.matcher(linkHref).matches() == true) {
System.out.println(linkHref);
set.add(linkHref);
}
} } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

试着弄了一下github,所以把这个非常不完美的项目放在了上面,就当练手,项目地址:https://github.com/Ai-yoo/Java_Applaction.git

Java爬虫爬取网站电影下载链接的更多相关文章

  1. 写一个python 爬虫爬取百度电影并存入mysql中

    目标是利用python爬取百度搜索的电影 在类型 地区 年代各个标签下 电影的名字 评分 和图片连接 以及 电影连接 首先我们先在mysql中建表 create table liubo4( id in ...

  2. 如何使用robots禁止各大搜索引擎爬虫爬取网站

    ps:由于公司网站配置的测试环境被百度爬虫抓取,干扰了线上正常环境的使用,刚好看到每次搜索淘宝时,都会有一句由于robots.txt文件存在限制指令无法提供内容描述,于是便去学习了一波 1.原来一般来 ...

  3. Python爬虫爬取豆瓣电影之数据提取值xpath和lxml模块

    工具:Python 3.6.5.PyCharm开发工具.Windows 10 操作系统.谷歌浏览器 目的:爬取豆瓣电影排行榜中电影的title.链接地址.图片.评价人数.评分等 网址:https:// ...

  4. python 爬虫&爬取豆瓣电影top250

    爬取豆瓣电影top250from urllib.request import * #导入所有的request,urllib相当于一个文件夹,用到它里面的方法requestfrom lxml impor ...

  5. java爬虫爬取网页内容前,对网页内容的编码格式进行判断的方式

    近日在做爬虫功能,爬取网页内容,然后对内容进行语义分析,最后对网页打标签,从而判断访问该网页的用户的属性. 在爬取内容时,遇到乱码问题.故需对网页内容编码格式做判断,方式大体分为三种:一.从heade ...

  6. webmagic 二次开发爬虫 爬取网站图片

    webmagic的是一个无须配置.便于二次开发的爬虫框架,它提供简单灵活的API,只需少量代码即可实现一个爬虫. webmagic介绍 编写一个简单的爬虫 webmagic的使用文档:http://w ...

  7. python3 爬虫---爬取豆瓣电影TOP250

    第一次爬取的网站就是豆瓣电影 Top 250,网址是:https://movie.douban.com/top250?start=0&filter= 分析网址'?'符号后的参数,第一个参数's ...

  8. 一个简单java爬虫爬取网页中邮箱并保存

    此代码为一十分简单网络爬虫,仅供娱乐之用. java代码如下: package tool; import java.io.BufferedReader; import java.io.File; im ...

  9. java爬虫爬取的html内容中空格(&nbsp;)变为问号“?”的解决方法

    用java编写的爬虫,使用xpath爬取内容后,发现网页源码中的 全部显示为?(问号),但是使用字符串的replace("?", ""),并不能替换,网上找了一 ...

随机推荐

  1. JDBC批量插入优化addbatch

    // 获取要设置的Arp基准的List后,插入Arp基准表中 public boolean insertArpStandardList(List<ArpTable> list) { Con ...

  2. sqoop:mysql和Hbase/Hive/Hdfs之间相互导入数据

    1.安装sqoop 请参考http://www.cnblogs.com/Richardzhu/p/3322635.html 增加了SQOOP_HOME相关环境变量:source ~/.bashrc  ...

  3. python导入模块

    1.模块的定义: 模块定义:用来逻辑上组织python代码(变量.函数.类.逻辑:目的是:实现一个功能),本质就是.py结尾的python文件. 补充: 包的定义:用来从逻辑组织模块的,本质就是一个目 ...

  4. Android WebView 缓存机制和模式详解

    当我们加载Html时候,会在我们data/应用package下生成database与cache两个文件夹: 我们请求的Url记录是保存在webviewCache.db里,而url的内容是保存在webv ...

  5. UTF-8 的BOM带来的麻烦

    UTF-8 的BOM带来的麻烦 工作需要我用程序生成一个html文件. 由于服务器端使用apache+Tomcat来执行html和jsp文件. 开始生成html文件放在apache目录下,页面无法默认 ...

  6. AM335x(TQ335x)学习笔记——使用dtb方式启动内核

    老式的u-boot使用ATAGS的方式启动linux内核,本文使用新式的dtb方式启动内核. 我使用的内核是linux-3.17.2版本,下面开始编译内核. (1) 解压内核 [php] view p ...

  7. C#中的匿名函数使用,类名<T>

    C#中有个叫做"泛型"的集合,就是说只是个外壳,到底是int,string,bool还是什么类型,都可以按照自己的要求进行定义集合,所以我们用个"T"表示. 请 ...

  8. Flex中利用单选按钮切换柱状图横纵坐标以及描述

    1.问题描述 一组单选按钮,有周和月之分,选择"周",柱状图横坐标显示的是周,纵坐标显示的是人数:选择"月",柱状图横坐标显示的月,纵坐标显示的是比率. 2.演 ...

  9. 结合实例分析Android MVP的实现

    最近阅读项目的源码,发现项目中有MVP的痕迹,但是自己却不能很好地理解相关的代码实现逻辑.主要原因是自己对于MVP的理解过于概念话,还没有真正操作过.本文打算分析一个MVP的简单实例,帮助自己更好的理 ...

  10. Luogu345: [POI2007]POW-The Flood

    题意 见luogu Sol 贪心 从小到大枚举高度,把小于等于这一高度的相邻格子用并查集合并 那么这个集合内的所有格子都一定可以由这个集合内的一个最低点抽完水 那么合并之后(一定要在合并之后) 判断这 ...