当前位置: 首页 > news >正文

C#抓取网页数据分析

首先将网页内容整个抓取下来,数据放在byte[]中(网络上传输时形式是byte),进一步转化为String,以便于对其操作,实例如下:
private static string GetPageData(string url)
{
if (url == null || url.Trim() == "")
return null;
WebClient wc = new WebClient();//定义
wc.Credentials = CredentialCache.DefaultCredentials;
Byte[] pageData = wc.DownloadData(url);
return Encoding.Default.GetString(pageData);//.ASCII.GetString
}

上面只是简单地获取网页数据,但网页中还存在编码问题,这时候为了避免乱码问题,就需要进行处理了,代码如下:

//url是要访问的网站地址,charSet是目标网页的编码,如果传入的是null或者"",那就自动分析网页的编码
private string GetPageData(string url, string charSet)
{
string strWebData = string.Empty;
if (url != null || url.Trim() != "")
{
WebClient myWebClient = new WebClient();
//创建WebClient实例myWebClient
// 需要注意的:
//有的网页可能下不下来,有种种原因比如需要cookie,编码问题等等
//这是就要具体问题具体分析比如在头部加入cookie
// webclient.Headers.Add("Cookie", cookie);
//这样可能需要一些重载方法。根据需要写就可以了
//获取或设置用于对向 Internet 资源的请求进行身份验证的网络凭据。
myWebClient.Credentials = CredentialCache.DefaultCredentials;
//如果服务器要验证用户名,密码
//NetworkCredential mycred = new NetworkCredential(struser, strpassword);
//myWebClient.Credentials = mycred;
//从资源下载数据并返回字节数组。(加@是因为网址中间有"/"符号)
byte[] myDataBuffer = myWebClient.DownloadData(url);
strWebData = Encoding.Default.GetString(myDataBuffer);
//获取网页字符编码描述信息
Match charSetMatch = Regex.Match(strWebData, "<meta([^<]*)charset=([^<]*)\"", RegexOptions.IgnoreCase | RegexOptions.Multiline);
string webCharSet = charSetMatch.Groups[2].Value;
if (charSet == null || charSet == "")
{
//如果未获取到编码,则设置默认编码
if (webCharSet == null || webCharSet == "")
{
charSet = "UTF-8";
}
else
{
charSet = webCharSet;
}
}
if (charSet != null && charSet != "" && Encoding.GetEncoding(charSet) != Encoding.Default)
{
strWebData = Encoding.GetEncoding(charSet).GetString(myDataBuffer);
}
}
return strWebData;
}

得到了数据的字符串形式,然后可以对网页进行解析了(其实就是对字符串的各种操作和正则表达式的应用):
// 解析页面,查找链接
// 此处尚需扩展,还有某些形式的链接不被识别
string strRef = @"(href|HREF|src|SRC|action|ACTION|Action)[ ]*=[ ]*[""'][^""'#>]+[""']";
MatchCollection matches = new Regex(strRef).Matches(strResponse);
strStatus += "找到: "+matches.Count+" 个链接\r\n";

上面的例子将网页中的链接解析出来,strRef变量表示了正则表达式的模式,变量matches表示符合匹配的项目的集合,后面的Regex(strRef).Matches(strResponse)就是创建正则规则使得strResponse里符合strRef模式的字符串都返回。然后调用matches的变量就可以取得各种信息了。
当然,这里只能识别一些基本的链接形式,像script中的链接和一些不带“”的链接都没有被支持,这个的扩展还是比较简单的。

常用的的解析还有以下几种:
//获取标题
Match TitleMatch = Regex.Match(strResponse, "<title>([^<]*)</title>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
title = TitleMatch.Groups[1].Value;

//获取描述信息
Match Desc = Regex.Match(strResponse, "<Meta name=\"DESCRIPTION\" content=\"([^<]*)\">", RegexOptions.IgnoreCase | RegexOptions.Multiline);
strdesc = Desc.Groups[1].Value;

//获取网页的大小
size = strResponse.Length;

//去除Html标签

private string StripHtml(string strHtml)
{
Regex objRegExp = new Regex("<(.|\n)+?>");
string strOutput = objRegExp.Replace(strHtml, "");
strOutput = strOutput.Replace("<", "&lt;");
strOutput = strOutput.Replace(">", "&gt;");
return strOutput;
}
有些例外会使得去除不干净,所以建议连续两次转化。这样将Html标签转化为了空格。太多连续的空格会影响之后对字符串的操作。所以再加入这样的语句:
//把所有空格变为一个空格
Regex r = new Regex(@"\s+");
wordsOnly = r.Replace(strResponse, " ");
wordsOnly.Trim();
写的不简单,但我还可以看的明白,注意using System.Text;
using System.Text.RegularExpressions;要写上
实际应用中:我做测试,获取一个区的气象部门的天气预报情况

private static string GetPageData(string url)//获取url字符串的方法
{
if (url == null || url.Trim() == "")
return null;
WebClient wc = new WebClient();
wc.Credentials = CredentialCache.DefaultCredentials;
Byte[] pageData = wc.DownloadData(url);
return Encoding.Default.GetString(pageData);//.ASCII.GetString
}

protected void Button1_Click(object sender, EventArgs e)
{
string strResponse = GetPageData(TextBox1 .Text );
string strRef = @"(href|HREF|src|SRC|action|ACTION|Action)[ ]*=[ ]*[""'][^""'#>]+[""']";
MatchCollection matches = new Regex(strRef).Matches(strResponse);//在strResponse匹配的字符串
TextBox2.Text = "找到: " + matches.Count + " 个链接\r\n";
   //以上为仿照学习例子,测试是否成功,果然成功,下面为应用
string strRef2 = @"MARQUEE";//定义关键字符串,我原来在要获得数据的网页上看到的关键字,看html源就行
TextBox3.Text = strResponse.Substring(strResponse.IndexOf(strRef2,2800)+120, 135).ToString();
  //strResponse字符串中截取从strResponse.IndexOf(strRef2,2800)+120开始的 135个字符。
}
测试:我在TextBox1 .Text 中输入:http://www.py121.com/weathe.jsp,那么,立刻可以获得天气情况的报道文字了,这就是最基本的c#抓取类了。
最后还需要小小修改哦。因为有些时候在字符不确定性就要做调整,譬如该天气情况,有时候没有这么多字符显示,你硬要显示,则会出错哦。我的源码段
//抓天气情况
string strResponse = GetPageData("http://www.py121.com/weathe.jsp");
string strRef2 = @"MARQUEE";
string str_last_index = strResponse.Substring(strResponse.IndexOf(strRef2, 2800) + 113, 70).Trim().ToString();
if (str_last_index.IndexOf('时') > 1)//091110发现始终不能解决两个 '时' 出现的问题,所以10行后有修改正版
{
get_weathe = strResponse.Substring(strResponse.IndexOf(strRef2, 2800) + 113, str_last_index.IndexOf('时') + 2).Trim().ToString();//字符串从IndexOf(strRef2, 2800) + 113开始,'时'为标志结束
}
else
{
get_weathe = strResponse.Substring(strResponse.IndexOf(strRef2, 2800) + 113, 60).Trim().ToString();
}
这次主要利用了indexof判断 '时'在字符出现的位置,解决了有时候不能显示的漏洞
get_weathe为全局变量,到时候就可以在前台用javascript调用了。ok

091110更新为

if (str_last_index.IndexOf('时') > 1)
{
if (str_last_index.IndexOf('时') < 50)//判断是否 '时' 在字符串中 大于1索引,但又不止一个 '时'
{
get_weathe = strResponse.Substring(strResponse.IndexOf(strRef2, 2800) + 113, str_last_index.LastIndexOf ('时') + 10).Trim().ToString();//字符串从IndexOf(strRef2, 2800) + 113开始,'时'为标志结束
}
else
{
get_weathe = strResponse.Substring(strResponse.IndexOf(strRef2, 2800) + 113, str_last_index.IndexOf('时') + 2).Trim().ToString();//字符串从IndexOf(strRef2, 2800) + 113开始,'时'为标志结束
}
}
else
{
get_weathe = strResponse.Substring(strResponse.IndexOf(strRef2, 2800) + 113, 60).Trim().ToString();
}
当然,我们还可以抓取某网站数据的变化更新,这要用到output&&input 数据库.
该例子的关键还是:对字符串的各种操作和正则表达式的应用


简单介绍一下WebClient:
WebClient 类提供向 URI 标识的任何本地、Intranet 或 Internet 资源发送数据以及从这些资源接收数据的公共方法。
WebClient 类使用 WebRequest 类提供对资源的访问。WebClient 实例可以通过任何已向 WebRequest.RegisterPrefix 方法注册的 WebRequest 子代访问数据。
注意
默认情况下,.NET Framework 支持以 http:、https:、ftp:、和 file: 方案标识符开头的 URI。

下面描述用于将数据上载到资源的 WebClient 方法:
OpenWrite检索一个用于将数据发送到资源的 Stream。
OpenWriteAsync检索 Stream,它在不阻止调用线程的情况下将数据发送到资源。
UploadData将字节数组发送到资源,并返回包含任何响应的 Byte 数组。
UploadDataAsync在不阻止调用线程的情况下,将 Byte 数组发送到资源。
UploadFile将本地文件发送到资源,并返回包含任何响应的 Byte 数组。
UploadFileAsync在不阻止调用线程的情况下,将本地文件发送到资源。
UploadValues将 NameValueCollection 发送到资源,并返回包含任何响应的 Byte 数组。
UploadValuesAsync在不阻止调用线程的情况下,将 NameValueCollection 发送到资源,并返回包含任何响应的 Byte 数组。
UploadString在不阻止调用线程的情况下,将 String 发送到资源。
UploadStringAsync在不阻止调用线程的情况下,将 String 发送到资源。

下面描述从资源下载数据的 WebClient 方法:
OpenRead从资源以 Stream 的形式返回数据。
OpenReadAsync在不阻止调用线程的情况下,从资源返回数据。
DownloadData从资源下载数据并返回 Byte 数组。
DownloadDataAsync在不阻止调用线程的情况下,从资源下载数据并返回 Byte 数组。
DownloadFile从资源将数据下载到本地文件。
DownloadFileAsync在不阻止调用线程的情况下,将数据从资源下载到本地文件。
DownloadString从资源下载 String 并返回 String。
DownloadStringAsync在不阻止调用线程的情况下,从资源下载 String。

您可以使用 CancelAsync 方法取消尚未完成的异步操作。
默认情况下,WebClient 实例不发送可选的 HTTP 报头。如果您的请求需要可选报头,必须将该报头添加到 Headers 集合。例如,要在响应中保留查询,必须添加用户代理报头。此外,如果用户代理标头丢失,服务器可能返回 500(内部服务器错误)。
在 WebClient 实例中,AllowAutoRedirect 设置为 true。
给继承者的说明 派生类应调用 WebClient 的基类实现,以确保派生类按预期方式工作。
例如:

C# 利用WebClient类盗取站点(http://www.ip138.com)手机号信息

首先我们每个人都想查对方的手机所在地及属于什么类型卡,那我们利用C#封装的类WebClient,NameValueCollection,Regex等分别属于的命名空间是using System.Net、using System.Text、using System.Collections.Specialized、using System.Text.RegularExpressions。是在Vs2005环境下测试,下面代码测试如下:
private void InitWeaOne()
    {
3 WebClient wb = new WebClient();
4 NameValueCollection myNameValueCollection = new NameValueCollection();
5
6 myNameValueCollection.Add("mobile", "13777483912");
7 myNameValueCollection.Add("action", "mobile");
8 byte[] pagedata = wb.UploadValues  (http://www.ip138.com:8080/search.asp, myNameValueCollection);
9 string result = Encoding.Default.GetString(pagedata);
10 string pat = "tdc2>([^<]*)</TD>";
11 Regex r = new Regex(pat, RegexOptions.IgnoreCase);
12 Match m = r.Match(result);
13 string[] strInfo = new string[3] { "", "", "" };
14 int i = 0;
15 while (m.Success)
16 {
17 if (i < strInfo.Length)
18 {
19 strInfo[i] = m.ToString().Substring(5);
20 }
21 m = m.NextMatch();
22 i++;
23 }
24 string a = strInfo[0].ToString();
25 string g = strInfo[1].ToString();
26 string f = strInfo[2].ToString();
27
28 }

相关文章:

  • POJ 3301
  • 几个常用Request.ServerVariables的中文
  • CodeForces 132C 一道简单 dp
  • 详解C#正则表达式语法的相关规则
  • PHP-cli简介
  • 致创业者的一封信(转)
  • DOM(转)
  • 修改文件注册数据库连接配置,可不在Net Manager里配置
  • Apache+Mod_Python配置
  • 【BestCoder】【Round#29】
  • struts2Demo
  • 总有一款合适你--ARM下裸机开发环境大全
  • 关于javascript原型链的个人理解
  • 项目管理学习笔记二:信息系统服务管理
  • Monkey源码分析之事件源
  • java正则表式的使用
  • MYSQL 的 IF 函数
  • MySQL-事务管理(基础)
  • NSTimer学习笔记
  • Service Worker
  • Spring-boot 启动时碰到的错误
  • underscore源码剖析之整体架构
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • vue:响应原理
  • 程序员该如何有效的找工作?
  • 从零开始的无人驾驶 1
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 前端学习笔记之观察者模式
  • 让你的分享飞起来——极光推出社会化分享组件
  • 事件委托的小应用
  • 通过几道题目学习二叉搜索树
  • 微信公众号开发小记——5.python微信红包
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 怎样选择前端框架
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 说说我为什么看好Spring Cloud Alibaba
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • # 飞书APP集成平台-数字化落地
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #HarmonyOS:Web组件的使用
  • #includecmath
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #微信小程序:微信小程序常见的配置传值
  • (13)Hive调优——动态分区导致的小文件问题
  • (搬运以学习)flask 上下文的实现
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (五)c52学习之旅-静态数码管
  • (一一四)第九章编程练习
  • (转)人的集合论——移山之道
  • (转)为C# Windows服务添加安装程序
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • *** 2003