网络爬虫(专门抓取图片)

xmfdsh我真是兴趣多多,怎么老是静不下心来搞定一方面的技术,再学点其他的东西,循序渐进,好吧,我又研究网络爬虫去了,这是一个简单版的,参考了网上很多资料,C#来编写,专门抓取图片,能够抓取一些需要cookie的网站,所以功能上还是挺完善的,xmfdsh只研究了三天,因此还有大把需要改进的地方,日后再
慢慢改进,在本文后面附上整个项目,在此献给喜欢研究C#的朋友们,让我慢慢地道来:


#region 访问数据 + Request(int index)
/// <summary>
/// 访问数据
/// </summary>
private void Request(int index)
{
try
{
int depth;
string url = "";
//lock锁住Dictionary,因为Dictionary多线程会出错
lock (_locker)
{
//查看是否还存在未下载的链接
if (UnDownLoad.Count <= 0)
{
_workingSignals.FinishWorking(index);
return;
}
//否则的话,把该虫子标记为在工作
_reqsBusy[index] = true;
depth = UnDownLoad.First().Value;
url = UnDownLoad.First().Key;

IsDownLoad.Add(url, depth);//将URL 加入到已经下载集合里
UnDownLoad.Remove(url);
}
//网络协议的东西,不懂网上搜一下,(HttpWebRequest)的使用
//这个需要一点日子理解,xmfdsh不是一下子就弄懂
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Accept = "text/html";
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)";
request.CookieContainer = cookies;//cookie 尝试

RequestState rs = new RequestState(request, url, depth, index);
//回调函数,如果接受到数据的处理方法
var result = request.BeginGetResponse(new AsyncCallback(Received), rs);
//也是回调函数,超时的回调函数
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, TimeOut, rs, MAXTIME, true);
}
catch (Exception ex)
{
_reqsBusy[index] = false;
DispatchWork();
}

}
#endregion

首先上来的是请求某个连接的方法,里面有两个回调函数,说明这里的编程时异步的,这个异步编程个人觉得需要花点时间去了解和学习,这个不是一朝一夕的,个人觉得C#比较难的地方就在一些接口,工具类,还有异步事件等等。


#region 超时的方法 + TimeOut(object state, bool timedOut)
/// <summary>
/// 超时的方法
/// </summary>
/// <param name="state"></param>
/// <param name="timedOut"></param>
private void TimeOut(object state, bool timedOut)
{
//判断是否超时
if (timedOut)
{
RequestState rs = state as RequestState;
if (rs != null)
{
//撤销internet请求
rs.Request.Abort();
}
DispatchWork();
}
}
#endregion

这个是超时的方法,当超时的时候,默认撤销internet的请求,并回滚,所以这个链接下的东西就没有了,当然超时后,继续请求下一个链接的资源


#region 获取数据 异步 + Received(IAsyncResult ar)
/// <summary>
/// 获取数据 异步
/// </summary>
/// <param name="ar"></param>
private void Received(IAsyncResult ar)
{

try
{
//得到请求进来的参数
RequestState rs = (RequestState)ar.AsyncState;
HttpWebRequest request = rs.Request;
string url = rs.Url;

//获取响应
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
if (response != null && response.StatusCode == HttpStatusCode.OK)//成功获取响应
{
//得到资源流
Stream responseStream = response.GetResponseStream();
rs.ResponseStream = responseStream;
//处理读取数据的异步方法 ReceivedData
var result = responseStream.BeginRead(rs.Data, 0, rs.BufferSize, new AsyncCallback(ReceivedData), rs);
}
//响应失败
else
{
response.Close();
rs.Request.Abort();
_reqsBusy[rs.Index] = false;
DispatchWork();
}
}
catch (Exception ex)
{
RequestState rs = (RequestState)ar.AsyncState;
_reqsBusy[rs.Index] = false;
DispatchWork();

}
}
#endregion

这个是收到了网站响应的时候做的事情,当然用到了异步来请求的话,数据也只能异步的读取,因此有了ReceivedData方法来接受数据,并处理,如果出错或者获取相应失败,相应的,回滚,并把该爬虫虫子的工作状态重新置为准备状态,为下一个链接做好准备。


        #region 异步操作读写 + ReceivedData(IAsyncResult ar)
/// <summary>
/// 异步操作读写
/// </summary>
/// <param name="ar">异步操作状态</param>
private void ReceivedData(IAsyncResult ar)
{

//获取异步状态参数
RequestState rs = (RequestState)ar.AsyncState;
HttpWebRequest request = rs.Request;
System.Net.HttpWebResponse responseImg = request.GetResponse() as System.Net.HttpWebResponse;
Stream responseStream = rs.ResponseStream;

string url = rs.Url;
int depth = rs.Depth;
string html = "";
int index = rs.Index;
int read = 1;
try
{
//如果改链接为图片来的,需要保存此图片
if (url.Contains(".jpg") || url.Contains(".png"))
{
read = responseStream.EndRead(ar);
if (read > 0)
{

MemoryStream ms = new System.IO.MemoryStream(rs.Data, 0, read);
BinaryReader reader = new BinaryReader(ms);

byte[] buffer = new byte[32 * 1024];
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
{
rs.memoryStream.Write(buffer, 0, read);

}
//递归 再次请求数据
var result = responseStream.BeginRead(rs.Data, 0, rs.BufferSize, new AsyncCallback(ReceivedData), rs);
return;
}
}
else
{
read = responseStream.EndRead(ar);
if (read > 0)
{
//创建内存流
MemoryStream ms = new MemoryStream(rs.Data, 0, read);
StreamReader reader = new StreamReader(ms, Encoding.GetEncoding("gb2312"));
string str = reader.ReadToEnd();
//添加到末尾
rs.Html.Append(str);
//递归 再次请求数据
var result = responseStream.BeginRead(rs.Data, 0, rs.BufferSize, new AsyncCallback(ReceivedData), rs);
return;
}

}
if (url.Contains(".jpg") || url.Contains(".png"))
{
//images = rs.Images;
SaveContents(rs.memoryStream.GetBuffer(), url);
}
else
{
html = rs.Html.ToString();
//保存
SaveContents(html, url);
//获取页面的链接
}
}
catch (Exception ex)
{

_reqsBusy[rs.Index] = false;
DispatchWork();
}
List<string> links = GetLinks(html,url);
//得到过滤后的链接,并保存到未下载集合
AddUrls(links, depth + 1);
_reqsBusy[index] = false;
DispatchWork();
}
#endregion

这个便是对数据的处理,这里就是重点的,其实也不难,判断是否为图片,如果为图片,保存此图片,因为目前网络爬虫做的还不够高级的时候爬图片是比较实际也比较好玩的(还不赶紧找找哪些网站有好多妹子图片),如果不是图片,我们认为它为普通html页面,便读取其中html代码,如果有发现有链接http或者href便加入到未下载链接中。当然读到的链接我们对一些js或者一些css等做了限制(不去读取这类东西)。


private void SaveContents(byte[] images, string url)
{

if (images.Count() < 1024*30)
return;
if (url.Contains(".jpg"))
{
File.WriteAllBytes(@"d:\网络爬虫图片\" + _index++ + ".jpg", images);
Console.WriteLine("图片保存成功" + url);
}
else
{
File.WriteAllBytes(@"d:\网络爬虫图片\" + _index++ + ".png", images);
Console.WriteLine("图片保存成功" + url);
}

}


#region 提取页面链接 + List<string> GetLinks(string html)
/// <summary>
/// 提取页面链接
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
private List<string> GetLinks(string html,string url)
{
//匹配http链接
const string pattern2 = @"http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
Regex r2 = new Regex(pattern2, RegexOptions.IgnoreCase);
//获得匹配结果
MatchCollection m2 = r2.Matches(html);
List<string> links = new List<string>();
for (int i = 0; i < m2.Count; i++)
{
//这个原因是w3school的网址,但里面的东西明显不是我们想要的
if (m2[i].ToString().Contains("www.w3.org"))
continue;
links.Add(m2[i].ToString());
}
//匹配href里面的链接,并加到主网址上(学网站的你懂的)
const string pattern = @"href=([""‘])?(?<href>[^‘""]+)\1[^>]*";
Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
//获得匹配结果
MatchCollection m = r.Matches(html);
// List<string> links = new List<string>();
for (int i = 0; i < m.Count; i++)
{
string href1 = m[i].ToString().Replace("href=", "");
href1 = href1.Replace("\"", "");
//找到符合的,添加到主网址(一开始输入的网址)里面去
string href = RootUrl + href1;
if (m[i].ToString().Contains("www.w3.org"))
continue;
links.Add(href);
}
return links;
}
#endregion

提取页面链接的方法,当读到发现这个为html代码的时候,继续解读里面的代码,找到里面的网址链接,也正是这样才有网络爬虫的功能(不然只能提取本页面就没意思了),其中http链接要提取就理所当然,href里面的话是因为。。。。(学网站你们懂的,不好解释)里面放的几乎都是图片,文章,因此才有了上面要处理href这类代码。


#region 添加url到 UnDownLoad 集合 + AddUrls(List<string> urls, int depth)
/// <summary>
/// 添加url到 UnDownLoad 集合
/// </summary>
/// <param name="urls"></param>
/// <param name="depth"></param>
private void AddUrls(List<string> urls, int depth)
{
lock (_locker)
{
if (depth >= MAXDEPTH)
{
//深度过大
return;
}
foreach (string url in urls)
{
string cleanUrl = url.Trim();
int end = cleanUrl.IndexOf(‘ ‘);
if (end > 0)
{
cleanUrl = cleanUrl.Substring(0, end);
}
if (UrlAvailable(cleanUrl))
{
UnDownLoad.Add(cleanUrl, depth);

}
}
}
}
#endregion


#region 开始捕获 + DispatchWork()
/// <summary>
/// 开始捕获
/// </summary>
private void DispatchWork()
{

for (int i = 0; i < _reqCount; i++)
{
if (!_reqsBusy[i])
{
Request(i);
Thread.Sleep(1000);
}
}
}
#endregion

这个函数就是让那些虫子工作的,其中_reqCount的值是一开始弄上去的,其实形象理解就是你放出虫子的个数,这个程序里面我默认放的20,随时可以修改。说到某些网站需要cookie的话是通过一开始先访问输入的网址,当然也是用HttpWebRequest帮助类,cookies
= request.CookieContainer;
//保存cookies,在后面访问后续网址的时候就加上去就行了request.CookieContainer = cookies;//cookie
尝试。应用了cookie才能访问的网站的话,根网页是不需要的,也就好比百度图片的网址http://image.baidu.com/是不需要的,但如果很唐突的访问里面的图片的话就要附上cookie了,所以这个问题也解决,xmfdsh发现这个程序还是有一些网站不能去抓图,抓到一定数量就停了,具体原因不知道,后面再慢慢改进

附上源码:http://files.cnblogs.com/xmfdsh/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB.rar

网络爬虫(专门抓取图片),布布扣,bubuko.com

时间: 2024-08-26 23:53:25

网络爬虫(专门抓取图片)的相关文章

(插播)网络爬虫,抓取你想要得东西。

最近,有个朋友说,想在一些页面上获取一些关键性得信息.比如,电话,地址等等.一个个页面去找 又很麻烦.这时候,想起了 何不去用"爬虫"去抓取一些想要得东西.省事,省里.好,今天 我们就讲讲,关于爬虫得一些东西. 这里 自己也是,看了一些关于爬虫得知识,正好,这几日闲来没事.做了一个功能小得爬虫. 这里是使用 java来进行编写得  首先 我们来介绍下.使用得框架,jdk1.6,htmlparser.jar(java 经典访问html页面得类),httpclient-3.01.jar,l

网络爬虫(抓取)正则表达式

using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net;using System.Text;using System.Text.RegularExpressions;using System.Web;using System.Web.UI;using System.Web.UI.WebControls; namespace WebApplication8{ p

python网络爬虫之爬取图片

今天使用requests和BeautifulSoup爬取了一些图片,还是很有成就感的,注释可能有误,希望大家多提意见 import requests from bs4 import BeautifulSoup circle = requests.get('http://travel.quanjing.com/tag/12975/%E9%A9%AC%E5%B0%94%E4%BB%A3%E5%A4%AB') # 将获取的图片地址依次放入count中 count = [] # 将获取的网页内容放入Be

有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取

点这里 阅读目录 用 AngularJS(以及其它 JavaScript 框架)开发的 Web 站点不支持爬虫的抓取 解决方案 为什么公开我们的解决方案 实现 AngularJS 服务 结论 Prerender 服务能够为网络爬虫提供预先渲染的动态页面内容,解决了用 JavaScript 框架构建的 Web 站点不支持爬虫抓取的问题.本文详细描述了一种解决方案,尤其是提供了集成 Prerender 服务的 Docker 容器镜像. 如果你正在使用 AngularJS 构建一个面向大众消费者的应用

[Search Engine] 搜索引擎技术之网络爬虫

随着互联网的大力发展,互联网称为信息的主要载体,而如何在互联网中搜集信息是互联网领域面临的一大挑战.网络爬虫技术是什么?其实网络爬虫技术就是指的网络数据的抓取,因为在网络中抓取数据是具有关联性的抓取,它就像是一只蜘蛛一样在互联网中爬来爬去,所以我们很形象地将其称为是网络爬虫技术.其中网络爬虫也被称为是网络机器人或者是网络追逐者. 网络爬虫技术是搜索引擎架构中最为根本的数据技术,通过网络爬虫技术,我们可以将互联网中数以百亿计的网页信息保存到本地,形成一个镜像文件,为整个搜索引擎提供数据支撑. 1.

java如果模拟请求重启路由器(网络爬虫常用),还有java如何下载图片

我们如果在公司或家里使用网络爬虫去抓取自己索要的一些数据的时候,常常对方的网站有defence机制,会给你的http请求返回500错误,只要是相同IP就请求不到数据,这时候我们只能去重启路由器,这样IP地址会改变,网络爬虫就能正常工作了 下面是通过发送Socket请求来模拟路由器的重启指令: protected void rebotadsl() { try { BufferedOutputStream sender = null; String url = baseURL; URL target

python开发的 dht网络爬虫

使用 libtorrent 的python绑定库实现一个dht网络爬虫,抓取dht网络中的磁力链接. dht 网络简介 p2p网络 在P2P网络中,通过种子文件下载资源时,要知道资源在P2P网络中哪些计算机中,这些传输资源的计算机称作peer.在传统的P2P网络中,使用tracker服务器跟踪资源的peer.要下载资源,首先需要取得这些peer. dht网络 tracker服务器面临一些版权和法律问题.于是出现了DHT,它把tracker上的资源peer信息分散到了整个网络中.dht网络是由分布

C# 网络爬虫利器之Html Agility Pack如何快速实现解析Html

简介 现在越来越多的场景需要我们使用网络爬虫,抓取相关数据便于我们使用,今天我们要讲的主角Html Agility Pack是在爬取的过程当中,能够高效的解析我们抓取到的html数据. 优势 在.NET技术下,解析html工具也很多,比如很多人可能会使用htmlparser,或者微软的MSHTML,htmlparser虽然比较易上手,但是相对应的解析速度较慢,而Html Agility Pack解析速度相当快,并且开源,易用,它可以帮助我们解析html文档就像用XmlDocument类来解析xm

iOS—网络实用技术OC篇&amp;网络爬虫-使用java语言抓取网络数据

网络爬虫-使用java语言抓取网络数据 前提:熟悉java语法(能看懂就行) 准备阶段:从网页中获取html代码 实战阶段:将对应的html代码使用java语言解析出来,最后保存到plist文件 上一片文章已经介绍我们可以使用两个方式来抓取网络数据实现网络爬虫,并且大致介绍了一下怎么使用正则表达式去实现数据的抓取 由于笔者曾经学过一段时间java和android相关的技术,今天就讲讲怎么使用java去抓取网络数据,关于Python有机会等笔者好好研究一下再来分享,但其实会一种就可以,除非你的需求