C#通過正則表達(dá)式實現(xiàn)提取網(wǎng)頁中的圖片
目前在做項目中有處理圖片的部分,參考了一下網(wǎng)上案例,自己寫了一個獲取內(nèi)容中的圖片地址的方法。
一般來說一個 HTML 文檔有很多標(biāo)簽,比如“<html>”、“<body>”、“<table>”等,想把文檔中的 img 標(biāo)簽提取出來并不是一件容易的事。由于 img 標(biāo)簽樣式變化多端,使提取的時候用程序?qū)ふ也⒉蝗菀?。于是想要尋找它們就必須寫一個非常健全的正則表達(dá)式,不然有可能會找得不全,或者找出來的不是正確的 img 標(biāo)簽。
我們可以從 HTML 標(biāo)簽的格式去想應(yīng)該怎么建這個正則表達(dá)式。首先要想一下 img 標(biāo)簽有幾種寫法,忽略大小寫不看的話,下面列出 img 標(biāo)簽可能出現(xiàn)的幾種情況。
<img> <img/> <img src=/>
這一些標(biāo)簽不用考慮,因為沒有圖片資源地址。
<img src = /images/pic.jpg/ > <img src =" /images/pic.jpg" > <img src= '/images/pic.jpg ' / >
這一些標(biāo)簽都有圖片資源地址,另外還有一個特點(diǎn)就是有引號對,可能為單引號,也可能為雙引號。因為不需要同時匹配引號對,所以正則表達(dá)式可以這么寫:@"<img\s*src\s*=\s*[""']?\s*(?[^\s""'<>]*)\s*/?\s*>"
<img width="320" height="240" src=/images/pic.jpg onclick="window.open('/images/pic.jpg')">
因為 img 和 src 之間可能會有其他的參數(shù),所以“<img”要有個單詞結(jié)束,比如說不能是“<imgabc”,同樣 src 前面也是一樣,使用單詞結(jié)束符“\b”有一個好處就是省去了表示空格的“\s*”。另外由于 img 標(biāo)簽中不可以出現(xiàn)“<”、“>”這樣的符號,所以要改寫前面的正則表達(dá)式:@"<img\b[^<>]*?\bsrc\s*=\s*[""']?\s*(?<imgUrl>[^\s""'<>]*)[^<>]*?/?\s*>"
<img width="320" height="240" src = "
/images/pic.jpg" />
像這種可能會用回車符折行的問題有時候會出現(xiàn),所以在有空格分開的地方要包含回車換行和 TAB 字符,另外在圖片地址中不能出現(xiàn)空格、TAB、回車和換行字符。
所以上面的正則表達(dá)式可以改成:@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>"
下面寫出取得HTML中所有圖片地址的類HvtHtmlImage:
using System.Text.RegularExpressions;
namespace HoverTree.HoverTreeFrame.HvtImage
{
public class HvtHtmlImage
{
/// <summary>
/// 取得HTML中所有圖片的 URL。
/// </summary>
/// <param name="sHtmlText">HTML代碼</param>
/// <returns>圖片的URL列表</returns>
public static string[] GetHvtImgUrls(string sHtmlText)
{
// 定義正則表達(dá)式用來匹配 img 標(biāo)簽
Regex m_hvtRegImg = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);
// 搜索匹配的字符串
MatchCollection matches = m_hvtRegImg.Matches(sHtmlText);
int m_i = 0;
string[] sUrlList = new string[matches.Count];
// 取得匹配項列表
foreach (Match match in matches)
sUrlList[m_i++] = match.Groups["imgUrl"].Value;
return sUrlList;
}
}
}
下面我們再來看一個例子
public Array MatchHtml(string html,string com)
{
List<string> urls = new List<string>();
html = html.ToLower();
//獲取SRC標(biāo)簽中的URL
Regex regexSrc = new Regex("src=\"[^\"]*[(.jpg)(.png)(.gif)(.bmp)(.ico)]\"");
foreach(Match m in regexSrc.Matches(html))
{
string src = m.Value;
src = src.Replace("src=","").Replace("\"","");
if (!src.Contains("http"))
src = com + src;
if(!urls.Contains(src))
urls.Add(src);
}
//獲取HREF標(biāo)簽中URL
Regex regexHref = new Regex("href=\"[^\"]*[(.jpg)(.png)(.gif)(.bmp)(.ico)]\"");
foreach (Match m in regexHref.Matches(html))
{
string href = m.Value;
href = href.Replace("href=", "").Replace("\"", "");
if (!href.Contains("http"))
href = com + href;
if(!urls.Contains(href))
urls.Add(href);
}
return urls.ToArray();
}
[DllImport("kernel32.dll")]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode);
[DllImport("kernel32.dll")]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int mode);
[DllImport("kernel32.dll")]
static extern IntPtr GetStdHandle(int handle);
const int STD_INPUT_HANDLE = -10;
const int ENABLE_QUICK_EDIT_MODE = 0x40 | 0x80;
public static void EnableQuickEditMode()
{
int mode; IntPtr handle = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(handle, out mode);
mode |= ENABLE_QUICK_EDIT_MODE;
SetConsoleMode(handle, mode);
}
static void Main(string[] args)
{
EnableQuickEditMode();
int oldCount = 0;
Console.Title = "TakeImageFromInternet";
string path = "E:\\Download\\loading\\";
while (true)
{
Console.Clear();
string countFile = "E:\\CountFile.txt";//用來計數(shù)的文本,以至于文件名不重復(fù)
int cursor = 0;
if (File.Exists(countFile))
{
string text = File.ReadAllText(countFile);
try
{
cursor =oldCount = Convert.ToInt32(text);//次數(shù)多了建議使用long
}
catch { }
}
Console.Write("please input a url:");
string url = "http://www.baidu.com/";
string temp = Console.ReadLine();
if (!string.IsNullOrEmpty(temp))
url = temp;
Match mcom = new Regex(@"^(?i)http://(\w+\.){2,3}(com(\.cn)?|cn|net)\b").Match(url);//獲取域名
string com = mcom.Value;
//Console.WriteLine(mcom.Value);
Console.Write("please input a save path:");
temp = Console.ReadLine();
if (Directory.Exists(temp))
path = temp;
Console.WriteLine();
WebClient client = new WebClient();
byte[] htmlData = null;
htmlData = client.DownloadData(url);
MemoryStream mstream = new MemoryStream(htmlData);
string html = "";
using (StreamReader sr = new StreamReader(mstream))
{
html = sr.ReadToEnd();
}
Array urls = new MatchHtmlImageUrl().MatchHtml(html,com);
foreach (string imageurl in urls)
{
Console.WriteLine(imageurl);
byte[] imageData = null;
try
{
imageData = client.DownloadData(imageurl);
}
catch { }
if (imageData != null && imageData.Length>0)
using (MemoryStream ms = new MemoryStream(imageData))
{
try
{
string ext = Aping.Utility.File.FileOpration.ExtendName(imageurl);
ImageFormat format = ImageFormat.Jpeg;
switch (ext)
{
case ".jpg":
format = ImageFormat.Jpeg;
break;
case ".bmp":
format = ImageFormat.Bmp;
break;
case ".png":
format = ImageFormat.Png;
break;
case ".gif":
format = ImageFormat.Gif;
break;
case ".ico":
format = ImageFormat.Icon;
break;
default:
continue;
}
Image image = new Bitmap(ms);
if (Directory.Exists(path))
image.Save(path + "\\" + cursor + ext, format);
}
catch(Exception ex) { Console.WriteLine(ex.Message); }
}
cursor++;
}
mstream.Close();
File.WriteAllText(countFile, cursor.ToString(), Encoding.UTF8);
Console.WriteLine("take done...image count:"+(cursor-oldCount).ToString());
}
}
相關(guān)文章
DevExpress實現(xiàn)GridControl刪除所有行的方法
這篇文章主要介紹了DevExpress實現(xiàn)GridControl刪除所有行的方法,對于C#初學(xué)者有一定的參考借鑒價值,需要的朋友可以參考下2014-08-08
使用Deflate算法對文件進(jìn)行壓縮與解壓縮的方法詳解
本篇文章是對使用Deflate算法對文件進(jìn)行壓縮和解壓縮的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
基于使用遞歸推算指定位數(shù)的斐波那契數(shù)列值的解決方法
本篇文章介紹了,基于使用遞歸推算指定位數(shù)的斐波那契數(shù)列值的解決方法。需要的朋友參考下2013-05-05
C# TextBox控件實現(xiàn)只能輸入數(shù)字的方法
這篇文章主要介紹了C# TextBox控件實現(xiàn)只能輸入數(shù)字的方法,本文使用TextBox的keypress事件實現(xiàn)這個需求,需要的朋友可以參考下2015-06-06
C#調(diào)用C++的dll兩種實現(xiàn)方式(托管與非托管)
這篇文章主要介紹了C#調(diào)用C++的dll兩種實現(xiàn)方式(托管與非托管),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08

