您的位置:首页 > 理论基础 > 计算机网络

基于Java的简单网络爬虫的实现--下载Silverlight视频

2012-05-17 00:15 1006 查看
       最近在CSDN上游荡,看到首页有个WP专区,点开后是关于微软的Windows Phone 7的各种开发资料。一时心血来潮,点开“四天玩转Windows Phone 7开发视频教程”的链接,点了下视频,发现要安装silverlight才能观看。所以就想先把它们下载下来,但NND发现这些个东东是用silverlight框架播放的,居然无法下载。但咱是谁啊,苦X兼苦X的程序员啊,有啥子事情是咱做不来的,于是右键查看源代码,可以看到

initParams:"SVP_{0}=c_69b409f9e1234b0abc8040841ecd7521,
VideoUri=http://download.microsoft.com/download/7/1/0/710733A5-5BE6-436E-AC7D-A265170CBB4B/Series_
Introduction_Day_1_Part_1_subtitle.wmv,ThumbUri=http://msdn.microsoft.com/zh-cn/windowsphone/hh39
5103.1_1b(l=zh-cn).jpg,Title=系列简介,HideFullBrowser=true,EmbedEnabled=true,EmbedCssWidth=400,Em
bedCssHeight=320,EmbedXapUri=http://msdn.microsoft.com/objectforward/default.aspx,Author=,Brand=,
Locale=,StartMode=AutoLoad,Persistence=None,MSNVideoUUID=,PTID=,HeaderColor=#06a4de,HighlightColo
r=#06a4de,MoreLinkColor=#0066dd,LinkColor=#0066dd,LoadingColor=#06a4de,GetUri=http://msdn.microso
ft.com/areas/sto/services/labrador.asmx,FontsToLoad=http://i3.msdn.microsoft.com/areas/sto/conten
t/silverlight/Microsoft.Mtps.Silverlight.Fonts.SegoeUI.xap;segoeui.ttf


 好啦,大家请看第二行的VideoUri=http://download.microsoft.com/download/7/1/0/710733A5-5BE6-436E-AC7D-A265170CBB4B/Series_Introduction_Day_1_Part_1_subtitle.wmv,发现了吧,以wmv结尾的,把地址复制下粘贴到浏览器或者迅雷,OK,直接下载。
         但是网站上有七八十个视频,总不能一个个点开然后查看源代码找到以wmv结尾的URL复制到迅雷再下载吧。答案当然是NO,NO,NO,谁让咱是伟大而苦X的程序员啊。大家应该知道搜索引擎是怎么检索信息的吧,没错就是网络爬虫,它是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本。虽然网络上有很多前辈们写的开源而强大的网络爬虫,但本着学习的态度,还是自己动手写吧。
        我们就以这个地址为初始节点吧:http://msdn.microsoft.com/zh-cn/windowsphone/hh182984,里面是所有的视频地址,右键查看源代码为了方便查看,我把其中不需要的元素删除了。
<a href="http://msdn.microsoft.com/windowsphone/hh768215">(1)从 XNA 到 SLXNA</a>
<a href="http://msdn.microsoft.com/windowsphone/hh768217">(2)将 FAS 添加到 XNA</a>
<a href="http://msdn.microsoft.com/windowsphone/hh768227">(3)将 FAS 添加到一个典型的Silverlight 应用程序中</a>
<a href="http://msdn.microsoft.com/windowsphone/hh768228">(4)添加次方块</a>
<a href="http://msdn.microsoft.com/windowsphone/hh768230">(6)使用实时摄像头原始数据</a>
<a href="http://msdn.microsoft.com/windowsphone/hh768231">(7)对次方块和深度 Toast 使用推送通知</a>
<a href="http://msdn.microsoft.com/windowsphone/hh968968">(8)使用代码优先本地数据库</a>
  上面的地址就是我们需要的,但怎么把它们全抓出来呢,首先就是将初始节点网页内容全部下载。这里为了方便,没有将抓取到的网页内容写入文件。
public static  String getNetPage(String starturl){
//starturl="http://msdn.microsoft.com/zh-cn/windowsphone/hh182984"
StringBuilder page =new StringBuilder("");
try {
URL url=new URL(starturl);
URLConnection connection=url.openConnection();
InputStream in=connection.getInputStream();
InputStreamReader reader=new InputStreamReader(in,"UTF-8");
BufferedReader bufferedReader=new BufferedReader(reader);
String line=null;
while ((line=bufferedReader.readLine())!=null) {
page.append(line)
.append("\n");
}
System.out.println(page);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return page.toString();
}
   OK,网页内容有了,下面就是怎么将所需的地址取出来。这里使用正则表达式,下面的正则表达式怎么样。
public static ArrayList<String> getUrlFromPage(String page){
ArrayList<String> list=new ArrayList<String>();
String regex="http://msdn.microsoft.com/windowsphone/hh[0-9]{6}";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(page);

while (matcher.find()) {
String url=matcher.group();
System.out.println(url);
list.add(url);
}
return list;
}


  细心的读者可能会发现网页里许多不是视频地址的地址也被我们抓取到了。
<a href="http://msdn.microsoft.com/windowsphone/hh395103"><img align="top" alt="" src="http://i.msdn.microsoft.com/hh395033.1_1(zh-cn,MSDN.10).jpg" title="Windows Phone 视频" /></a>
<a href="http://msdn.microsoft.com/windowsphone/hh398252"><img align="top" alt="" src="http://i.msdn.microsoft.com/hh395033.1_2(zh-cn,MSDN.10).jpg" title="Windows Phone 视频" /></a>
<a href="http://msdn.microsoft.com/windowsphone/hh398439"><img align="top" alt="" src="http://i.msdn.microsoft.com/hh395033.1_3(zh-cn,MSDN.10).jpg" title="Windows Phone 视频" /></a><
<a href="http://msdn.microsoft.com/windowsphone/hh417688"><img align="top" alt="" src="http://i.msdn.microsoft.com/hh395033.1_4(zh-cn,MSDN.10).jpg" title="Windows Phone 视频" />

   这当然不是我们想要的结果。而且大家看到每个视频地址后都有关于此视频的标题,我们能不能将标题一块抓取过来,将之与视频地址对应。
public static ArrayList<HashMap<String,String>> getUrlFromPage(String page){
ArrayList<HashMap<String,String>> list=new ArrayList<HashMap<String,String>>();
String regex="http://msdn.microsoft.com/windowsphone/hh[0-9]{6}\">[^x00-xff][0-9]+[^x00-xff][^6]*</a>";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(page);

while (matcher.find()) {
String url=matcher.group();
System.out.println(url);
HashMap<String,String> map=new HashMap<String,String>();
String[] s=url.split("\">");
map.put("index",s[1]);
map.put("url",s[0]);

list.add(map);
}
return list;
}
   下面是打印的结果。
http://msdn.microsoft.com/windowsphone/hh768215">(1)从 XNA 到 SLXNA</a> http://msdn.microsoft.com/windowsphone/hh768217">(2)将 FAS 添加到 XNA</a> http://msdn.microsoft.com/windowsphone/hh768227">(3)将 FAS 添加到一个典型的Silverlight 应用程序中</a> http://msdn.microsoft.com/windowsphone/hh768228">(4)添加次方块</a> http://msdn.microsoft.com/windowsphone/hh768229">(5)添加后台代理程序</a> http://msdn.microsoft.com/windowsphone/hh768230">(6)使用实时摄像头原始数据</a> http://msdn.microsoft.com/windowsphone/hh768231">(7)对次方块和深度 Toast 使用推送通知</a> http://msdn.microsoft.com/windowsphone/hh968968">(8)使用代码优先本地数据库</a> http://msdn.microsoft.com/windowsphone/hh968969">(9)后台音频</a> http://msdn.microsoft.com/windowsphone/hh395103">(1)系列简介</a> http://msdn.microsoft.com/windowsphone/hh398252">(2)安装 Visual Studio 2010 Express for Windows Phone</a> http://msdn.microsoft.com/windowsphone/hh398439">(3)编写您的第一个 Windows Phone 7 应用程序</a> http://msdn.microsoft.com/windowsphone/hh417688">(4)Windows Phone 7 仿真器概述</a> http://msdn.microsoft.com/windowsphone/hh417718">(5)详解您编写的第一个应用程序</a> http://msdn.microsoft.com/windowsphone/hh417729">(6)管理项目文件并理解编译和部署</a> http://msdn.microsoft.com/windowsphone/hh417730">(7)Visual Studio 2010 Express for Windows Phone IDE 概述</a> http://msdn.microsoft.com/windowsphone/hh417732">(8)使用项目</a> http://msdn.microsoft.com/windowsphone/hh417735">(9)声明变量和赋值</a> http://msdn.microsoft.com/windowsphone/hh417890">(10)从文本框中接受输入和赋值</a> http://msdn.microsoft.com/windowsphone/hh417892">(11)if 判断语句</a> http://msdn.microsoft.com/windowsphone/hh417893">(12)运算符、表达式和语句</a> http://msdn.microsoft.com/windowsphone/hh417894">(13)switch 判断语句</a> http://msdn.microsoft.com/windowsphone/hh417895">(14)for iteration 语句</a> http://msdn.microsoft.com/windowsphone/hh417896">(15)创建和调用简单的 Helper 方法</a> http://msdn.microsoft.com/windowsphone/hh417897">(16)家庭作业</a> http://msdn.microsoft.com/windowsphone/hh417898">(17)家庭作业解决方案</a> http://msdn.microsoft.com/windowsphone/hh417899">(1)处理字符串</a> http://msdn.microsoft.com/windowsphone/hh417901">(2)使用 DateTime</a> http://msdn.microsoft.com/windowsphone/hh417902">(3)理解和创建类</a> http://msdn.microsoft.com/windowsphone/hh417903">(4)使用 .NET Framework 类库中的类</a> http://msdn.microsoft.com/windowsphone/hh417904">(5)理解命名空间</a> http://msdn.microsoft.com/windowsphone/hh417905">(6)使用集合</a> http://msdn.microsoft.com/windowsphone/hh417906">(7)对象和集合初始值设定项</a> http://msdn.microsoft.com/windowsphone/hh417908">(8)在 XAML 设计器和代码窗口中工作</a> http://msdn.microsoft.com/windowsphone/hh417909">(9)理解 XAML 语法</a> http://msdn.microsoft.com/windowsphone/hh417910">(10)Silverlight 布局控件</a> http://msdn.microsoft.com/windowsphone/hh417911">(11)处理 Silverlight 事件</a> http://msdn.microsoft.com/windowsphone/hh417912">(12)Silverlight 输入控件</a> http://msdn.microsoft.com/windowsphone/hh417913">(13)家庭作业</a> http://msdn.microsoft.com/windowsphone/hh417914">(14)家庭作业解决方案 - 第1 部分</a> http://msdn.microsoft.com/windowsphone/hh417916">(15)家庭作业解决方案 - 第2 部分</a> http://msdn.microsoft.com/windowsphone/hh417917">(1)使用图像控件</a> http://msdn.microsoft.com/windowsphone/hh417918">(2)处理资源和样式</a> http://msdn.microsoft.com/windowsphone/hh417923">(3)在 XAML 页面之间浏览和传递数据</a> http://msdn.microsoft.com/windowsphone/hh417924">(4)使用应用程序栏</a> http://msdn.microsoft.com/windowsphone/hh417925">(5)利用 Canvas 作为对话框</a> http://msdn.microsoft.com/windowsphone/hh417926">(6)理解独立存储</a> http://msdn.microsoft.com/windowsphone/hh417927">(7)独立存储、ListBox 和数据模板</a> http://msdn.microsoft.com/windowsphone/hh417928">(8)逻辑删除和任务切换</a> http://msdn.microsoft.com/windowsphone/hh418008">(9)添加不同的输入值范围</a> http://msdn.microsoft.com/windowsphone/hh418009">(10)GPS、位置 API 和调用 Web 服务</a> http://msdn.microsoft.com/windowsphone/hh418010">(11)图像背景、方向更改和控件可见性</a> http://msdn.microsoft.com/windowsphone/hh418011">(12)家庭作业</a> http://msdn.microsoft.com/windowsphone/hh418012">(13)家庭作业解决方案</a> http://msdn.microsoft.com/windowsphone/hh418013">(1)简介</a> http://msdn.microsoft.com/windowsphone/hh418014">(2)开始活动</a> http://msdn.microsoft.com/windowsphone/hh418015">(3)MainPage 初始设置</a> http://msdn.microsoft.com/windowsphone/hh418016">(4)创建注释命名约定</a> http://msdn.microsoft.com/windowsphone/hh418017">(5)将 Note Class 绑定到 ListBox DataTemplate</a> http://msdn.microsoft.com/windowsphone/hh418018">(6)添加注释页面初始设置</a> http://msdn.microsoft.com/windowsphone/hh418019">(7)调用 TerraService Web 服务</a> http://msdn.microsoft.com/windowsphone/hh418020">(8)保存新注释</a> http://msdn.microsoft.com/windowsphone/hh418021">(9)ViewEdit 页面初始设置</a> http://msdn.microsoft.com/windowsphone/hh418022">(10)在 MainPage 与 ViewEdit 页面之间导航</a> http://msdn.microsoft.com/windowsphone/hh418023">(11)在 ViewEdit 页面上切换到Edit 模式并保存更改</a> http://msdn.microsoft.com/windowsphone/hh418024">(12)ViewEdit 页面的删除注释功能</a> http://msdn.microsoft.com/windowsphone/hh418025">(13)在 MainPage 上添加帮助屏幕</a> http://msdn.microsoft.com/windowsphone/hh418026">(14)存储应用程序状态第 1 部分- MainPage</a> http://msdn.microsoft.com/windowsphone/hh418027">(15)存储应用程序状态第 2 部分 - Add 页面</a> http://msdn.microsoft.com/windowsphone/hh418028">(16)存储应用程序状态第 3 部分 - ViewEdit 页面</a> http://msdn.microsoft.com/windowsphone/hh418029">(17)调试空白文件名问题</a> http://msdn.microsoft.com/windowsphone/hh418030">(18)代码清理、异常处理和市场准备</a> http://msdn.microsoft.com/windowsphone/hh418031">(19)相关内容</a>[/code]    但这还不是我们期望的结果,没关系,接着来

public static String getWMVFromURL(String page){
String suburl = null;
String regex="http://download.microsoft.com/download[^\\u4e00-\\u9fa5]+\\.(wmv)";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(page);

while (matcher.find()) {
suburl=matcher.group();

}
return suburl;
}

  下面是主函数

public static void main(String[] args){
String url="http://msdn.microsoft.com/zh-cn/windowsphone/hh182984";
String page=getNetPage(url);
ArrayList<HashMap<String,String>> list;
list=getUrlFromPage(page);

for (int i = 0; i < list.size(); i++) {
String suburl=list.get(i).get("url");
String subpage=getNetPage(suburl);
String wmvurl=getWMVFromURL(subpage);
System.out.println("wmvurl="+i+"="+wmvurl);
}
}

   大家可以对此优化一下,可以使用多线程。

   另外需要说明的是如果只是使用我上面的方法是不能正确抓取到视频地址的,需要加上诸如User-Agent:用户浏览器与版本信息、Referer:请求URL的源地址或Cookie:用于辨别用户身份,存储在用户的数据等信息,这是为了防止网络爬虫可能频繁访问网站影响网站性能。而之所以写这篇博文,只是提供一种如何抓取网页URL的思想。

  文章中如有错误或不当之处,还请指正。若是大牛看到,就当是一笑话了。




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息