被管理員和諧了的最高票答案“知乎數據抓取程序”(.net、c#數據挖掘)
來源:程序員人生 發布時間:2015-03-04 08:49:08 閱讀次數:4414次
問:能利用爬蟲技術做到哪些很酷很有趣很有用的事情?
準備學習python爬蟲。各位大神都會用爬蟲做哪些有趣的事情?
今天突然想玩玩爬蟲,就提了這個問題。隨著YouTube上的1個tutor寫了個簡單的程序,爬了1點豆瓣的數據。主要用到request和bs4(BeautifulSoup)模塊。雖然簡陋,畢竟是
人生中的第1只爬蟲啊……以示記念,代碼寫在博客里了:我的第1只爬蟲:爬取豆瓣讀書
沒想到第1次答題竟然登上了知乎互聯網專欄的榜首了,也上了知乎首頁,惋惜被和諧了。



答:
監測她(他)的知乎,她關注、回答、贊了某個問題立馬電腦和手機都彈出提示是否是很酷!先上兩張圖:


我是個.NET程序猿,有1天女神告知我有1個很不錯的社區叫“知乎”,我常常1過來就看到她在看知乎,但每次我想看她都看了啥啊,她就遮住屏幕不讓我看。因而乎,在我心里埋下了1顆強烈的好奇心。知乎中搜了下她的名字,經過各種挑選知道了她的知乎空間。第1時間出現的想法是我要寫個監測程序,她關注的所有問題我都想知道。
連續奮戰5小時,至清晨3點程序終究寫出來了。主要HttpWebRequest加正則表達式來抓取數據,程序開機自動運行,數據庫設在1臺24小時開機的服務器上。多個監測客戶端同時運行,公司的,家里的,遠程服務器上的。每隔5分鐘自動循環讀取1次數據,如果檢測到關注了新的問題,立馬將它們發送至我的QQ郵箱和我的163郵箱,大家都知道QQ郵箱有提示功能,1發過來,立馬會彈出1個窗體告知你有新的郵件。手機qq客戶端也有,所以不管我是在上班的路上,還是在電腦旁,只要她有新動態我立馬就知道了。是否是很酷?
監測程序已運行3個多月了,搜集了他23百個關注的問題,我知道她1般都是吃中飯或晚餐前喜歡看1下知乎,晚上睡前會看會,她睡得早但偶爾清晨1點多還看知乎。她關注情感類的問題最多,而且那段時間我1直在追她,所以我能根據她關注的問題來推測她的1些想法,包括約會聊天時我可以聊1些她感興趣的話題。所以實用性還是比較強的。
假設某1天清晨1點,手機突然響了1下,發現她關注了某個問題。立馬給她發1條短信過去,你是否是還沒睡啊?
是啊,你怎樣知道我沒睡的? 憑感覺! 嘿嘿。 然后漸漸靠近她關注的那個話題去聊,這是否是會讓她感覺到你特別懂她。好奇你竟然知道她睡沒睡,好奇你和她聊的話那末符合她的心聲。
如此利器,有誰想要的嗎? 贊超過1百,程序和源代碼都放知乎上同享。
====21日9:37更新=====
沒想到第1次答題就上榜了,好不開心,來來來,別停哈。怒上榜首,我開源12306搶票源碼。我先赴約去開源我的知乎監測程序吧,1會把鏈接發過來。謝謝大家的贊!


===============
====21日11:50更新=====
《關于隱私》
先說明下,很多人都說我這樣做侵犯隱私?沒有吧,這些數據都是公然的啊,她也知道我關注了她呀,但蛋疼的知乎客戶端沒有這么細致的提示功能,我乃至在客戶端上找不到我都關注了哪些人。知乎手機app開發團隊弱爆了,這么強有力的需求竟然沒有滿足?
而且,知乎!你怎樣就沒有定閱功能呢?郵箱定閱! 我提出來啦哈,采用了給我大V可好?
《關于匿不匿名》
FK,男子漢大丈夫,匿啥名啊。女神知道了就知道了,又不是做甚么喪盡天良的事,敢作敢當!之所以寫這么1個程序,也其實不是完全的偷窺心理。對1個程序員來講,寫出1個新鮮的程序是能給程序員1種很大的樂趣的,這1般人難以理解,想當年在學校時,通宵寫俄羅斯方塊,白天上課不聽課在那研究1個方塊當按左鍵是甚么模樣甚么邏輯,右鍵又怎樣。這是非常成心思的事,編程實際上是1個藝術活,好的框架和優良的代碼讓人1看就感覺特別享受。
所以我寫這么個程序一樣也是滿足自己的1種樂趣。沒必要匿!
《關于女神追到沒?》
追到啦,哈哈!好爽啊,9月份去騎了趟川藏線,路遇佛像及經輪,我就祈禱我要娶她做老婆。且動身前找牛逼大神算了1卦(中國易學協會副會長),說我10月份很有姻緣緣分。因而,我在世界3大冰川之1的-來古冰川的河床上找了1下午的石頭,終究找到1顆天然紅色心形的愛情石,回來后我就拿著石頭跟她表白了,然后就成了!雖然她說我表白像檢討1樣,但也很感人!
惋惜,我們在1起沒多久就分手了。緣由1兩句話說不完,總之不管以后怎樣。都祝愿她,雖然在1起不長時間,但那是很美的回想。我會收藏!
===================
=====2015⑴⑵1 上午11:16分更新=======
程序開源地址:
下載源程序:http://download.csdn.net/detail/wuyidexinsheng/8382253
程序博文地址:http://blog.csdn.net/wuyidexinsheng/article/details/42964707
步入正題,思路描寫:
下來源程序后,先自己去建數據庫改配置哈,否則程序運行不起來的。
<span style="font-size:10px;"><?xml version="1.0"?>
<configuration>
<appSettings>
<!--數據有兩種存儲方式,1種存儲于本地程序目錄下的Ids.txt,但那只存了問題ID,完全的數據存于oracle
數據庫中-->
<add key="connStr" value="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=DZZH)));User Id=xxxxx;Password=xxxx"/>
<!-- 設置監測循環時間:秒 -->
<add key="Interval" value="600"/>
<!--設置自動發送信息機器人郵箱-->
<add key="smtpAddress" value="smtp.163.com"/>
<!--用戶名-->
<add key="sendEmailFrom" value="xxxxxxxx@163.com"/>
<!--密碼-->
<add key="sendEmailFromPwd" value="xxxxxxxxx"/>
<!--接收郵箱地址-->
<add key="strMailAddressTo" value="xxxxxxxx@163.com,xxxxxxxx@qq.com"/>
<!--郵件名稱抬頭-->
<add key="EmailName" value="zhApp-家里電腦"/>
<!--END-->
<!--監測地址-->
<add key="WatchingURL" value="http://www.zhihu.com/people/wu-xin-sheng⑺"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration></span>
第1步:通過Cinser.Common.HttpHelper.GetString(“www.zhihu.com/people/wu-xin-sheng⑺”)讀取給定的1個網址的后臺代碼:
結果以下圖所示:

如我空間的源碼中就有這么1段:
<span class="name">伍新生</span>,<span class="bio" title="5顏6色的情感,我終生的尋求!">5顏6色的情感,我終生的尋求!</span>
</div>
</div>
<div class="body clearfix">
<div class="zm-profile-header-avatar-container self">
<img alt="伍新生"
src="http://pic4.zhimg.com/94cc60166_l.jpg"
class="zm-profile-header-img zg-avatar-big zm-avatar-editor-preview"/>
<span class="zm-entry-head-avatar-edit-button">修改頭像</span>
第2步:通過調用方法private List<Question> GetQuestions(string source)截取關鍵數據。
原理很簡單,所有知乎的問題都是以下的格式:<aclass="question_link"target="_blank"href="/question/27621722/answer/37636385">能利用爬蟲技術做到哪些很酷很有趣很有用的事情?</a>
接下來那就是字符串截取唄:調用Cinser.Common.StringPlus.SubString(source, “<a class="question_link”, "</a>")等順次截取問題的ID,名稱等數據。
private List<Question> GetQuestions(string source)
{
List<Question> questions = new List<Question>();
string startStr = "<a class="question_link"";
if (source.IndexOf(startStr) != ⑴)
{
Question q = new Question();
string content = Cinser.Common.StringPlus.SubString(source, startStr, "</a>");
q.Id = Cinser.Common.StringPlus.SubString(content, "question/", """);
q.Title = content.Substring(content.IndexOf(">") + 1);
q.Time = DateTime.Now;
questions.Add(q);
source = source.Substring(source.IndexOf(startStr) + startStr.Length);
questions.AddRange(GetQuestions(source));
}
return questions;
}
第3步:將取到的問題寫入
數據庫,并寫入本地Ids.txt。
由于5分鐘讀取1次數據,肯定會讀取到部份已度過的數據咯。就是通過取到id然后看Ids.txt里面這個id是否是已存在了,如果存在了就表示已抓去過啦。
為何問題都已寫到oracle數據庫了還要往本地Ids.txt寫1次呢,由于oracle數據庫是部署在遠程服務器上的啊。如果這臺服務器突然出故障死機了,怎樣辦?程序還得要運行啊,所以程序往兩個地方都寫1次數據。如果oracle數據庫不能訪問,則通過讀取和寫入本地ids來記錄問題。
數據抓取其實就這么簡單。
以下是部份源碼,也能夠直接去下載源程序:http://download.csdn.net/detail/wuyidexinsheng/8382253
以下是程序主窗體源碼:
public partial class Form1 : Form
{
DataProvider dal;
string watchingURL = string.Empty;
int LoopCount = 0;
public Form1()
{
InitializeComponent();
dal = new DataProvider();
dal.AddLog("程序啟動");
base.WindowState = FormWindowState.Minimized;
base.Show();
base.Hide();
base.WindowState = FormWindowState.Normal;
base.ShowInTaskbar = false;
base.TopMost = false;
base.MaximizeBox = false;
base.MinimizeBox = false;
base.ControlBox = false;
//設置循環監測時間
int interval = int.Parse(Cinser.Common.ConfigurationHelper.GetAppSettingsValue("Interval"));
timer1.Interval = interval * 1000;
watchingURL = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("WatchingURL");
RunWhenStart(true, "zhApp.exe", """ + Application.StartupPath + "zhApp.exe" AutoRun");
Run();
dal.AddLog("程序初始化成功");
LoopCount += 1;
}
//設置程序開機自啟動
public void RunWhenStart(bool Started, string name, string path)
{
RegistryKey HKLM = Registry.CurrentUser;
RegistryKey Run = HKLM.CreateSubKey(@"SOFTWAREMicrosoftWindowsCurrentVersionRun");
if (Started == true)
{
try
{
Run.SetValue(name, path);
HKLM.Close();
}
catch(Exception ex)//沒有權限會異常
{
throw ex;
}
}
else
{
try
{
Run.DeleteValue(name);
HKLM.Close();
}
catch (Exception ex)//沒有權限會異常
{
throw ex;
}
}
}
/// <summary>
/// 運行監測流程
/// </summary>
private void Run()
{
List<Question> questions = GetQuestions(Cinser.Common.HttpHelper.GetString(watchingURL));
string ids = dal.GetExistIdsStr();
for (int i = 0; i < questions.Count; i++)
{
if (ids.IndexOf(questions[i].Id) != ⑴)
{
questions.Remove(questions[i]);
i--;
}
else
{
if (ids == string.Empty)
ids = questions[i].Id;
else
ids += "," + questions[i].Id;
}
}
if (questions.Count > 0)
{
SendQuestions(questions);
dal.WriteIdStrToTxt(ids);
dal.Add(questions);
dal.AddLog(string.Format("獲得了{0}條新數據。", questions.Count));
}
}
/// <summary>
/// 從監測站點源數據中抓取問題
/// </summary>
private List<Question> GetQuestions(string source)
{
List<Question> questions = new List<Question>();
string startStr = "<a class="question_link"";
if (source.IndexOf(startStr) != ⑴)
{
Question q = new Question();
string content = Cinser.Common.StringPlus.SubString(source, startStr, "</a>");
q.Id = Cinser.Common.StringPlus.SubString(content, "question/", """);
q.Title = content.Substring(content.IndexOf(">") + 1);
q.Time = DateTime.Now;
questions.Add(q);
source = source.Substring(source.IndexOf(startStr) + startStr.Length);
questions.AddRange(GetQuestions(source));
}
return questions;
}
private bool SendQuestions(List<Question> questions)
{
bool bSuccess = true;
List<string> strMailAddressTo = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("strMailAddressTo").Split(',').ToList();
string smtpAddress = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("smtpAddress");
string sendEmailFrom = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("sendEmailFrom");
string sendEmailFromPwd = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("sendEmailFromPwd");
string emailName = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("EmailName");
//密碼解密,開源的話就去掉這步吧,這樣配置的時候直接配置明文密碼就行。
//sendEmailFromPwd = Cinser.Common.Security.DecryptDES(sendEmailFromPwd, "yuiophgf");
string msg = string.Empty;
SendCompletedEventHandler s = new SendCompletedEventHandler(SendCompleted);
string content = GetQustionsListStr(questions);
content += "
信息來源于:" + watchingURL;
Cinser.Common.SmtpEmailSend.SendEmail(strMailAddressTo, emailName + DateTime.Now.ToString(), content, smtpAddress, 0x19, sendEmailFrom, sendEmailFromPwd, "163測試郵箱", null, out msg, s);
return bSuccess;
}
private void SendCompleted(object sender, AsyncCompletedEventArgs e)
{
}
private string GetQustionsListStr(List<Question> questions)
{
string content = string.Empty;
if (questions != null && questions.Count > 0)
{
content = string.Format("名稱:{0},url:{1}", questions[0].Title, questions[0].Url);
for (int i = 1; i < questions.Count; i++)
{
content += string.Format("
名稱:{0},url:{1}", questions[i].Title, questions[i].Url);
}
}
return content;
}
private void timer1_Tick(object sender, EventArgs e)
{
int interval = int.Parse(Cinser.Common.ConfigurationHelper.GetAppSettingsValue("Interval"));
timer1.Interval = interval * 1000;
Run();
dal.AddLog(string.Format("程序循環次數:{0}", LoopCount++));
}
}
知乎問題model:Question.cs
public class Question
{
string id, title, url, type, remark;
DateTime time;
public string Remark
{
get { return remark; }
set { remark = value; }
}
public DateTime Time
{
get { return time; }
set { time = value; }
}
public string Type
{
get { return type; }
set { type = value; }
}
public string Url
{
get
{
if (string.IsNullOrEmpty(url))
{
url = string.Format("http://www.zhihu.com/question/{0}", Id);
}
return url;
}
set { url = value; }
}
public string Title
{
get { return title; }
set { title = value; }
}
public string Id
{
get { return id; }
set { id = value; }
}
}
數據操作類DataProvider.cs
/// <summary>
/// 知乎問題數據表操作Provider
/// </summary>
public class DataProvider
{
private string connStr = string.Empty;
Cinser.DBUtility.DAL.
OracleDALCommon dal;
string txtPath = "";
string logPath = "";
string debugPath = string.Empty;
public string DebugPath
{
get
{
if (debugPath == string.Empty)
debugPath = System.AppDomain.CurrentDomain.BaseDirectory;
if (debugPath.EndsWith("") == false)
{
debugPath += "";
}
return debugPath;
}
set { debugPath = value; }
}
public string LogPath
{
get
{
if (logPath == string.Empty)
{
logPath = DebugPath + "Log.txt";
}
return logPath;
}
}
public DataProvider()
{
dal = new Cinser.DBUtility.DAL.
OracleDALCommon(this.ConnStr);
}
public string TxtPath
{
get
{
if (txtPath == string.Empty)
{
txtPath = DebugPath + "Ids.txt";
}
return txtPath;
}
}
public string ConnStr
{
get
{
if (connStr == string.Empty)
{
connStr = Cinser.Common.ConfigurationHelper.GetAppSettingsValue("connStr");
}
return connStr;
}
set { connStr = value; }
}
public bool CanConnect
OracleServer
{
get
{
return dal.Open();
}
}
/// <summary>
/// 將抓取到的問題寫入oracle
數據庫中
/// </summary>
/// <param name="questions"></param>
/// <returns></returns>
public bool Add(List<Question> questions)
{
bool bReturn = false;
try
{
for (int i = 0; i < questions.Count; i++)
{
dal.Add("qustions", questions[i]);
}
bReturn = true;
}
catch { }
return bReturn;
}
public DataTable GetQustions(string sqlWhere = "1=1")
{
try
{
DataTable dt = dal.GetDataList("qustions", sqlWhere);
return dt;
}
catch
{
return null;
}
}
public bool IsExist(string id)
{
try
{
string sqlWhere = "id='" + id + "'";
DataTable dt = dal.GetDataList("qustions", sqlWhere);
return dt.Rows.Count > 0;
}
catch
{
return false;
}
}
/// <summary>
/// 獲得已抓取過的問題ID字符串
/// </summary>
/// <returns></returns>
public string GetExistIdsStr()
{
string ids = string.Empty;
//如果能連上遠程的oracle
服務器則從oracle
數據庫中取ID字符串
if (CanConnect
OracleServer)
{
DataTable dt = GetQustions();
if (dt != null &&
主站蜘蛛池模板:
午夜影院免费看
|
日本不卡高清中文字幕免费
|
欧美最猛黑人xxxxx猛交
|
最近中文字幕高清中文字幕在线看
|
一区视频在线播放
|
国产中文久久精品
|
欧美一区亚洲二区
|
国产一区二区免费不卡在线播放
|
久久精品一区二区三区资源网
|
男女激情视频软件
|
精品国产日韩久久亚洲
|
国产精品欧美日韩
|
中文字幕在线观看免费视频
|
91视频一区二区三区
|
一级亚洲
|
久久久久18|
国产成人精品久久一区二区三区
|
性做久久久久久久
|
国产亚洲福利一区二区免费看
|
久久伊人网站
|
亚欧成人毛片一区二区三区四区
|
外国美女一级片
|
欧美xxxx极品流血
|
国产精品欧美韩国日本久久
|
日本中文字幕乱码免费
|
欧美一级欧美一级高清
|
亚洲欧美日韩在线观看播放
|
国产偷v国产偷v国产
|
视频一区 国产
|
欧美一级欧美三级
|
最近最新在线中文字幕
|
中文字幕日本一本二本三区
|
亚洲区小说区图片区qvod
|
国产 日韩 一区
|
亚洲玖玖
|
国内精品伊人久久大香线焦
|
日本亚洲视频
|
欧美偷拍自拍视频
|
xxxx欧美视频|
亚洲欧美日韩综合在线一区二区三区
|
国产一区二区不卡
|