Google 图片下载工具
?????? 畢設做實驗需要從網上下幾萬張圖片,以前用師兄做的Flickr下載器,用Flickr的API完成的。但是Flickr上的圖片是用戶分享居多,通過指定的關鍵詞去搜索,很多時候無法得到滿意的圖片。在Google、Bing上雖然能得到比較好的搜索結果,但是Google早早地停用了搜索的SDK,CodeProject上的例子是N年前的,試過都不能用了;Bing雖然現在還有SDK,但是看官方的通告,大約是8月份也要停用了,而且現在提供的下載限制每天一張,木有辦法,只能自己想招了。
?????? 在查看Google圖片搜索頁面的源碼時,發現在<a>的href屬性里面包含了圖片原始的url,所以就想到解析搜索結果頁面的辦法,將原始圖片的url切出來,然后從url現在原始的圖片。url的切割,可以使用正則表達式來完成。
?????? 還有一個問題就是搜索結果頁面的獲取。
?????? 看了下搜索結果的url,發現在url里面包含了搜索關鍵字,以及其他的一些信息,于是想:是不是可以拼接字符串,然后向google發送web請求,返回結果可能就是搜索結果頁面吧。
?????? 這個url是直接復制瀏覽器搜索結果的url,然后替換掉q和oq兩個參數,其值為搜索關鍵詞。舉個例子,關鍵詞是answer,發送請求,保存返回的結果,得到如下頁面:
?????? 總過有21張圖片,可見Google對這種形式的web請求的返回結果做了一些限制,不可以像使用瀏覽器那樣,一次返回很多頁,只能一次返回21張。
?????? 然后,點了下分頁的“2”,看第二頁,發現url有了些變化:
?????? 關鍵在于這個start屬性!start=21,那應該是說,利用這個屬性來做的分頁,但是了,又不知道哪個屬性指定end,略郁悶。。。但還好了,至少可以說,在拼url的時候,可以通過指定start的值,發送多次請求,得到多個搜索結果分頁,雖然笨一點,但是目的還是達到了。
?????? Nice!
?????? 最后使用的url如下:
?????? q指定搜索關鍵詞,start索引各個分頁的起始位置。
?????? 以上就是編程在Google上搜索關鍵詞并下載圖片的基本思路。
?????? 有幾個問題還要記錄下:
?????? 1、搜索返回頁面的問題。
?????? 直接向Google發送請求,然后從搜索結果里面用RE分割url,耗費內存資源太多。實驗發現,一個搜索返回頁面200k,同時下載關鍵詞100個,每個關鍵詞下載200張,也就是10個頁面,如果都在內存里完成的話,不算光是存這些東西,就需要大約200M,還要用RE來切割url,實際跑的時候看了下,內存爆了都,我電腦是4G的內存。而且,由于網絡的問題,有時候下載過程會中斷,想了下,還是先把搜索結果存到本地,然后再切割url。
??????? 2、RE切割圖片的問題。
??????? RE學的不夠好,自己寫了幾個總是有問題,就在網上找了下面的一個:
??????? 這個只能切除url,還需要加一些后綴過濾,才能得到圖片的url。還在琢磨怎么寫一個高級的RE,直接把圖片的url切出來。
???????? 3、多線程下載的問題。
???????? 因為同時下載100多個關鍵詞的圖片,就想多線程來做,撇開網絡帶寬的問題,希望這樣能下載的快一點。初始的時候,每個關鍵詞開啟一個線程。但是這樣還是慢,每個關鍵詞下載額定200張的圖片,需要1-2個小時,當然,是在多個關鍵詞同時下的情況。72個關鍵詞,實際下到8000多張圖片,共計下了一晚上,6、7個小時吧。忍不了。。
??????? 后來,想著在每個關鍵詞下載過程中,給每個下載鏈接起一個線程。結果,由于同時起的線程過多,導致線程資源短缺,頻繁的有線程掛掉,雖然在一定的階段里,同等網絡條件下,確實下的快了,但是整體上卻是慢了。也嘗試了ThreadPool,情況類似。
??????? 我想的理想情況是,開200個線程,維護一個線程池,有需求就請求線程作業,作業完畢則釋放資源,如果當前沒有資源,則請求端等待,直到有可用線程。暫時沒有實現,最近要再搞一下。
??????? 此外,在下載中,還做了log,并對圖片重新編號,還有圖片名與url的映射字典。
??????? 以下附程序代碼:
???????
Program.cs?1?using?System;?2?using?System.Collections.Generic;
?3?using?System.IO;
?4?using?System.Linq;
?5?using?System.Threading;
?6?using?System.Windows.Forms;
?7?
?8?namespace?GoogleImageDownload
?9?{
10?????static?class?Program
11?????{
12?????????///?<summary>
13?????????///?應用程序的主入口點。
14?????????///?</summary>
15?????????[STAThread]
16?????????static?void?Main()
17?????????{
18?????????????StreamReader?sr?=?new?StreamReader("keywords.txt");
19?????????????string?keywordPool?=?sr.ReadToEnd();
20?????????????sr.Close();
21?????????????string[]?keywords?=?keywordPool.Split(new?char[]?{?','?});
22?????????????foreach?(string?keyword?in?keywords)
23?????????????{
24?????????????????GoogleImages?bi?=?new?GoogleImages();
25?????????????????Thread?download?=?new?Thread(new?ParameterizedThreadStart(bi.DownLoadImages));
26?????????????????download.Name?=?"Thread_"?+?keyword;
27?????????????????download.Start(keyword);
28?????????????????//WaitCallback?wc?=?new?WaitCallback(bi.DownLoadImages);
29?????????????????//ThreadPool.QueueUserWorkItem(wc,?keyword);
30?????????????}
31?????????}
32?????}
33?}
?
GoogleImages??1?using?System;??2?using?System.Collections.Generic;
??3?using?System.Net;
??4?using?System.Xml.Linq;
??5?using?System.IO;
??6?using?System.Web;
??7?using?System.Text.RegularExpressions;
??8?using?System.Threading;
??9?using?System.Drawing;
?10?using?System.Text;
?11?
?12?namespace?GoogleImageDownload
?13?{
?14?????public?class?GoogleImages
?15?????{
?16?????????///?<summary>
?17?????????///?通過拼url的方式,向google發出請求
?18?????????///?參數0:查詢關鍵字
?19?????????///?參數1:從那一條搜索記錄開始,每頁默認21個,通過設置為0、21、42、63等,獲取多張圖片
?20?????????///?</summary>
?21?????????private?const?string?IMG_URL?=?"http://www.google.com.hk/search?q={0}&hl=zh-CN&newwindow=1&safe=strict&biw=1280&"?+
?22?????????????"bih=699&gbv=2&ie=UTF-8&tbm=isch&ei=2HblT4vrCISwiQeavLhZ&start={1}&sa=N";
?23?????????///?<summary>
?24?????????///?默認POST?10?頁
?25?????????///?</summary>
?26?????????private?const?int?PAGES?=?10;
?27?????????///?<summary>
?28?????????///?提供四種出錯信息
?29?????????///?</summary>
?30?????????public?static?string[]?ERRORS?=?{?"GetDownloadInfo",?"CreateImageDownloadLink",?"SaveToLocal",?"RenameImage"?};
?31?????????private?string?logFile?=?"";
?32?????????private?string?downloadFolder?=?"";
?33?????????private?string?downloadObj?=?"";
?34?
?35?????????///?<summary>
?36?????????///?Download?images?from?Google
?37?????????///?</summary>
?38?????????public?void?DownLoadImages(object?Obj)
?39?????????{
?40?????????????DateTime?tStart?=?DateTime.Now;
?41?????????????this.downloadObj?=?(string)Obj;
?42?
?43?????????????///?Images:每個關鍵字為單獨的一個文件夾,該文件夾下保存圖片
?44?????????????///?DownloadInfos:POST得到的Google搜索結果的頁面,以及頁面中圖片的url
?45?????????????///?Log:下載圖片中出現的異常信息
?46?????????????#region?創建保存下載信息的文件夾
?47?
?48?????????????///?創建圖片文件夾
?49?????????????if?(!Directory.Exists(String.Format(".\\Images\\{0}",?downloadObj)))
?50?????????????{
?51?????????????????Directory.CreateDirectory(String.Format(".\\Images\\{0}",?downloadObj));
?52?????????????}
?53?????????????this.downloadFolder?=?String.Format(".\\Images\\{0}",?downloadObj);
?54?
?55?????????????///?創建下載信息文件夾
?56?????????????if?(!Directory.Exists(String.Format(".\\DownloadInfos",?downloadObj)))
?57?????????????{
?58?????????????????Directory.CreateDirectory(String.Format(".\\DownloadInfos",?downloadObj));
?59?????????????}
?60?
?61?????????????string?resHtmlFile?=?".\\DownloadInfos\\"?+?downloadObj?+?"_res.txt";
?62?????????????if?(!File.Exists(resHtmlFile))
?63?????????????{
?64?????????????????File.Create(resHtmlFile);
?65?????????????}
?66?
?67?????????????string?resImageList?=?".\\DownloadInfos\\"?+?downloadObj?+?"_img.txt";
?68?????????????if?(!File.Exists(resImageList))
?69?????????????{
?70?????????????????File.Create(resImageList);
?71?????????????}
?72?
?73?????????????///?創建日志文件夾
?74?????????????if?(!Directory.Exists(String.Format(".\\Log",?downloadObj)))
?75?????????????{
?76?????????????????Directory.CreateDirectory(String.Format(".\\Log",?downloadObj));
?77?????????????}
?78?
?79?????????????this.logFile?=?".\\Log\\"?+?(string)Obj?+?".log";
?80?????????????if?(!File.Exists(logFile))
?81?????????????{
?82?????????????????File.Create(logFile);
?83?????????????}
?84?
?85?????????????#endregion
?86?
?87?????????????///?確定下載幾頁,模擬了在搜索結果中手動翻頁
?88?????????????///?默認10頁,每頁大約21張圖片
?89?
?90?????????????#region?POST?10?個請求,返回10個Google搜索結果頁面,所有內容存在一個文本文件里面
?91?
?92?????????????for?(int?i?=?0;?i?<?PAGES;?i++)
?93?????????????{
?94?????????????????string?url?=?string.Format(IMG_URL,?downloadObj,?21?*?i);
?95?????????????????try
?96?????????????????{
?97?????????????????????System.Net.HttpWebRequest?r?=?(System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
?98?????????????????????r.AllowAutoRedirect?=?true;
?99?????????????????????System.Net.CookieContainer?c?=?new?System.Net.CookieContainer();
100?????????????????????r.CookieContainer?=?c;
101?????????????????????System.Net.HttpWebResponse?res?=?r.GetResponse()?as?System.Net.HttpWebResponse;
102?????????????????????if?(res.StatusCode?==?HttpStatusCode.OK)
103?????????????????????{
104?????????????????????????System.IO.StreamReader?s?=?new?System.IO.StreamReader(res.GetResponseStream(),?System.Text.Encoding.GetEncoding("GB2312"));
105?????????????????????????//Response.Write(s.ReadToEnd());
106?????????????????????????Console.WriteLine("start");
107?????????????????????????StreamWriter?sw?=?new?StreamWriter(resHtmlFile,?true);
108?????????????????????????sw.Write(s.ReadToEnd());
109?????????????????????????Console.WriteLine(downloadObj?+?"?"?+?i);
110?????????????????????????sw.Close();
111?????????????????????????s.Close();
112?????????????????????????res.Close();
113?????????????????????}
114?????????????????}
115?????????????????catch?(Exception?ex)
116?????????????????{
117?????????????????????PrintException(0,?downloadObj,?ex.ToString());
118?????????????????}
119?
120?????????????????Console.WriteLine("end");
121?????????????}
122?
123?????????????#endregion
124?
125?????????????#region?從文本文件中用RE切出圖片的url,并下載圖片
126?
127?????????????StreamReader?sr?=?new?StreamReader(resHtmlFile);
128?????????????string?result?=?sr.ReadToEnd();
129?????????????sr.Close();
130?
131?????????????///?一般網址url的RE
132?????????????string?strRegex?=?"(http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?";?
133?????????????Regex?re?=?new?Regex(strRegex);
134?????????????MatchCollection?mactes?=?re.Matches(result);
135?
136?????????????int?count?=?0;
137?????????????foreach?(Match?img?in?mactes)
138?????????????{
139?????????????????string?tmp?=?img.Value;
140?????????????????///?割掉RE得到的多余的內容
141?????????????????if?(tmp.Contains("&"))
142?????????????????????tmp?=?tmp.Substring(0,?tmp.Length?-?4);
143?????????????????///?過濾url,專找圖片的url
144?????????????????if?(tmp.Contains(".jpg")?||?tmp.Contains(".png")?||?tmp.Contains(".jpeg")?||?tmp.Contains(".gif"))
145?????????????????{
146?????????????????????string?newFileName?=?"";
147?????????????????????string[]?split?=?tmp.Split(new?char[]{'/'});
148?????????????????????///?給圖片分配一個新的名字
149?????????????????????try
150?????????????????????{
151?????????????????????????FileInfo?fi?=?new?FileInfo(split[split.Length?-?1]);
152?????????????????????????newFileName?=?String.Format("{0}_{1}{2}",?this.downloadObj,?count.ToString("000"),?fi.Extension);
153?????????????????????????count++;
154?????????????????????????///?輸出“newFileName????ImageUrl”到DownloadInfos
155?????????????????????????StreamWriter?sw2?=?new?StreamWriter(resImageList,?true);
156?????????????????????????sw2.WriteLine(String.Format("{0}\t{1}",?newFileName,?tmp));
157?????????????????????????sw2.Flush();
158?????????????????????????sw2.Close();
159?????????????????????}
160?????????????????????catch?(Exception?ex)
161?????????????????????{
162?????????????????????????PrintException(0,?split[split.Length?-?1],?ex.ToString());
163?????????????????????}
164?
165?????????????????????Console.WriteLine(split[split.Length-1]+"?is?downloading");
166?????????????????????/
167?????????????????????//?Download?Images?//
168?????????????????????/
169?????????????????????SavePhotoFromUrl(newFileName,?tmp);
170?????????????????????//ThreadPool.QueueUserWorkItem(new?WaitCallback(this.SavePhotoFromUrl),?new?string[]?{?newFileName,?tmp?});
171?????????????????????//Thread?save?=?new?Thread(new?ParameterizedThreadStart(this.SavePhotoFromUrl));
172?????????????????????//save.Name?=?"Thread_"?+?newFileName;
173?????????????????????//save.Start(new?string[]?{?newFileName,?tmp?});
174?????????????????????Console.WriteLine(split[split.Length-1]+"?has?been?downloaded");
175?????????????????}
176?????????????}
177?????????????
178?????????????#endregion
179?????????????
180?????????????///?輸出下載用時
181?????????????DateTime?tEnd?=?DateTime.Now;
182?????????????TimeSpan?cost?=?tEnd?-?tStart;
183?????????????PrintTime(cost.ToString());?
184?????????}
185?
186?????????///?<summary>
187?????????///?通過url將圖片保存到本地,指定文件名為FileName
188?????????///?</summary>
189?????????public?bool?SavePhotoFromUrl(string?FileName,?string?Url)
190?????????//public?void?SavePhotoFromUrl(Object?paras)
191?????????{
192?????????????//string[]?Para?=?(string[])paras;
193?????????????//string?FileName?=?Para[0];
194?????????????//string?Url?=?Para[1];
195?????????????bool?Value?=?false;
196?????????????WebResponse?response?=?null;
197?????????????Stream?stream?=?null;
198?
199?????????????try
200?????????????{
201?????????????????HttpWebRequest?request?=?(HttpWebRequest)WebRequest.Create(Url);
202?????????????????response?=?request.GetResponse();
203?????????????????stream?=?response.GetResponseStream();
204?????????????????Value?=?SaveBinaryFile(response,?this.downloadFolder?+?"\\"?+?FileName);
205?????????????}
206?????????????catch?(Exception?ex)
207?????????????{
208?????????????????PrintException(1,?Url,?ex.ToString());
209?????????????}
210?????????????return?Value;
211?????????}
212????????///?<summary>
213????????///?保存圖片到本地
214????????///?</summary>
215????????///?<param?name="response">用來保存圖片的Response</param>
216?????????private?bool?SaveBinaryFile(WebResponse?response,?string?FileName)
217?????????{
218?????????????bool?Value?=?true;
219?????????????byte[]?buffer?=?new?byte[1024];
220?
221?????????????try
222?????????????{
223?????????????????if?(File.Exists(FileName))
224?????????????????{
225?????????????????????return?true;
226?????????????????}
227?????????????????Stream?outStream?=?System.IO.File.Create(FileName);
228?????????????????Stream?inStream?=?response.GetResponseStream();
229?
230?????????????????int?l;
231?????????????????do
232?????????????????{
233?????????????????????l?=?inStream.Read(buffer,?0,?buffer.Length);
234?????????????????????if?(l?>?0)
235?????????????????????????outStream.Write(buffer,?0,?l);
236?????????????????}
237?????????????????while?(l?>?0);
238?
239?????????????????outStream.Close();
240?????????????????inStream.Close();
241?????????????}
242?????????????catch?(Exception?ex)
243?????????????{
244?????????????????PrintException(2,?FileName,?ex.ToString());
245?????????????????Value?=?false;
246?????????????}
247?????????????return?Value;
248?????????}
249?
250?????????///?<summary>
251?????????///?在下載過程中打印出錯信息
252?????????///?三種出錯信息:
253?????????///?0:GetDownloadInfo???????????在向Google請求下載信息的時候出錯
254?????????///?1:CreateImageDownloadLink???在獲取圖片url后建立連接過程中出錯
255?????????///?2:SaveToLocal???????????????在建立下載連接后保存到本地過程中出錯
256?????????///?3:?RenameImage???????????????按照標準命名方式重命名文件過程中出錯
257?????????///?</summary>
258?????????///?<param?name="type">出錯類型</param>
259?????????///?<param?name="obj">出錯對象</param>
260?????????///?<param?name="exceptionInfo">出錯信息</param>
261?????????private?void?PrintException(int?type,?string?obj,?string?exceptionInfo)
262?????????{
263?????????????try
264?????????????{
265?????????????????StreamWriter?sPrint?=?new?StreamWriter(this.logFile,?true);
266?????????????????sPrint.WriteLine(String.Format("TYPE:{0}\tOBJECT:[{1,-30}]\nERROR:{2}\n",?GoogleImages.ERRORS[type],?obj,?exceptionInfo));
267?????????????????sPrint.Close();
268?????????????}
269?????????????catch?(Exception?ex)
270?????????????{
271?????????????????;
272?????????????}
273?????????}
274?
275?????????///?<summary>
276?????????///?輸出下載所用時間
277?????????///?</summary>
278?????????///?<param?name="time">下載用時</param>
279?????????private?void?PrintTime(string?time)
280?????????{
281?????????????try
282?????????????{
283?????????????????StreamWriter?sPrint?=?new?StreamWriter(this.logFile,?true);
284?????????????????sPrint.WriteLine(String.Format("Download?Cost:{0}",time));
285?????????????????sPrint.Close();
286?????????????}
287?????????????catch?(Exception?ex)
288?????????????{
289?????????????????;
290?????????????}
291?????????}
292?????}
293?}
?
???????? 附:Google url中各個參數的含義(
http://www.4ucode.com/Study/Topic/1060948):
???????? hl(Interface Language):Google搜索的界面語言
???????? q(Query):查詢的關鍵詞
???????? start:顯示搜索結果的起始端,如果start=1,則從第2個搜索結果開始顯示;如果你想直接看第搜索結果第21頁,讓start=200即可,由于Google只顯示1000條搜索結果記錄,start理論取值范圍在0–999之間
???????? lr(Language Restrict):搜索內容的語言限定限定只搜索某種語言的網頁。如果lr參數為空,則為搜索所有網頁
???????? ie(Input Encoding):查詢關鍵詞的編碼,缺省設置為utf-8,也就是說請求Google搜索時參數q的值是一段utf-8編碼的文字
???????? oe(Output Encoding):搜索結果頁面的網頁編碼,缺省設置oe=utf-8
???????? num(Number):搜索結果顯示條數,取值范圍在10–100條之間,缺省設置num=10
???????? newwindow:是否開啟新窗口以顯示查詢結果,缺省設置newwindow=1,在新窗口打開搜索結果而面
???????? aq(Ascending Query):判斷搜索用戶是否是第一次查詢,如果用戶第一次進行查詢,則aq=f(First);如若進行過多次查詢,則aq=-1,這個的主要作用應該是統計和放置作-弊
???????? as_q(Ascending Search Query):上一次查詢關鍵詞
????????
???????? 歡迎指教&討論~
轉載于:https://www.cnblogs.com/YFYkuner/archive/2012/07/11/2587131.html
總結
以上是生活随笔為你收集整理的Google 图片下载工具的全部內容,希望文章能夠幫你解決所遇到的問題。