1. 程式人生 > >手把手教你用.NET Core寫爬蟲

手把手教你用.NET Core寫爬蟲

寫在前面

自從上一個專案58HouseSearch從.NET遷移到.NET core之後,磕磕碰碰磨蹭了一個月才正式上線到新版本。
然後最近又開了個新坑,搞了個Dy2018Crawler用來爬dy2018電影天堂上面的電影資源。這裡也藉機簡單介紹一下如何基於.NET Core寫一個爬蟲。
PS:如有偏錯,敬請指明…
PPS:該去電影院還是多去電影院,畢竟美人良時可無價。

準備工作(.NET Core準備)

首先,肯定是先安裝.NET Core咯。下載及安裝教程在這裡:.NET - Powerful Open Source Development。無論你是Windows、linux還是mac,統統可以玩。

我這裡的環境是:Windows10 + VS2015 community updata3 + .NET Core 1.1.0 SDK + .NET Core 1.0.1 tools Preview 2.

理論上,只需要安裝一下 .NET Core 1.1.0 SDK 即可開發.NET Core程式,至於用什麼工具寫程式碼都無關緊要了。

安裝好以上工具之後,在VS2015的新建專案就可以看到.NET Core的模板了。如下圖:

為了簡單起見,我們建立的時候,直接選擇VS .NET Core tools自帶的模板。

一個爬蟲的自我修養

分析網頁

寫爬蟲之前,我們首先要先去了解一下即將要爬取的網頁資料組成。

具體到網頁的話,便是分析我們要抓取的資料在HTML裡面是用什麼標籤抑或有什麼樣的標記,然後使用這個標記把資料從HTML中提取出來。在我這裡的話,用的更多的是HTML標籤的ID和CSS屬性。

以本文章想要爬取的dy2018.com為例,簡單描述一下這個過程。dy2018.com主頁如下圖:

在chrome裡面,按F12進入開發者模式,接著如下圖使用滑鼠選擇對應頁面資料,然後去分析頁面HTML組成。

接著我們開始分析頁面資料:

經過簡單分析HTML,我們得到以下結論:

  1. www.dy2018.com首頁的電影資料儲存在一個class為co_content222的div標籤裡面

  2. 電影詳情連結為a標籤,標籤顯示文字就是電影名稱,URL即詳情URL

那麼總結下來,我們的工作就是:找到class=’co_content222’ 的div標籤,從裡面提取所有的a標籤資料。

開始寫程式碼…

之前在寫58HouseSearch專案遷移到asp.net core簡單提過AngleSharp庫,一個基於.NET(C#)開發的專門為解析xHTML原始碼的DLL元件。

獲取電影列表資料
  private static HtmlParser htmlParser = new HtmlParser();

   private  ConcurrentDictionary<string, MovieInfo> _cdMovieInfo = new ConcurrentDictionary<string, MovieInfo>();
  private void AddToHotMovieList()
        {
            //此操作不阻塞當前其他操作,所以使用Task
            // _cdMovieInfo 為執行緒安全字典,儲存了當期所有的電影資料
            Task.Factory.StartNew(()=> 
            {
                try
                {
                    //通過URL獲取HTML
                    var htmlDoc = HTTPHelper.GetHTMLByURL("http://www.dy2018.com/");
                    //HTML 解析成 IDocument
                    var dom = htmlParser.Parse(htmlDoc);
                    //從dom中提取所有class='co_content222'的div標籤
                    //QuerySelectorAll方法接受 選擇器語法 
                    var lstDivInfo = dom.QuerySelectorAll("div.co_content222");
                    if (lstDivInfo !=null)
                    {
                        //前三個DIV為新電影
                        foreach (var divInfoin lstDivInfo.Take(3))
                        {
                            //獲取div中所有的a標籤且a標籤中含有"/i/"//Contains("/i/") 條件的過濾是因為在測試中發現這一塊div中的a標籤有可能是廣告連結
                            divInfo.QuerySelectorAll("a").Where(a => a.GetAttribute("href").Contains("/i/")).ToList().ForEach(
                            a =>
                            {
                                //拼接成完整連結
                                var onlineURL ="http://www.dy2018.com" + a.GetAttribute("href");
                                //看一下是否已經存在於現有資料中
                                if (!_cdMovieInfo.ContainsKey(onlineURL))
                                {
                                    //獲取電影的詳細資訊
                                    MovieInfo movieInfo = FillMovieInfoFormWeb(a, onlineURL);
                                    //下載連結不為空才新增到現有資料
                                    if (movieInfo.XunLeiDownLoadURLList !=null && movieInfo.XunLeiDownLoadURLList.Count !=0)
                                    {
                                         _cdMovieInfo.TryAdd(movieInfo.Dy2018OnlineUrl, movieInfo);
                                    }
                                }
                            });
                        }
                    }

                }
                catch(Exception ex)
                {

                }
            });
        }

獲取電影詳細資訊

 private MovieInfo FillMovieInfoFormWeb(AngleSharp.Dom.IElement a, string onlineURL)
        {
            var movieHTML = HTTPHelper.GetHTMLByURL(onlineURL);
            var movieDoc = htmlParser.Parse(movieHTML);
            //http://www.dy2018.com/i/97462.html 分析過程見上,不再贅述
            //電影的詳細介紹 在id為Zoom的標籤中
            var zoom = movieDoc.GetElementById("Zoom");
            //下載連結在 bgcolor='#fdfddf'的td中,有可能有多個連結
            var lstDownLoadURL = movieDoc.QuerySelectorAll("[bgcolor='#fdfddf']");
            //釋出時間 在class='updatetime'的span標籤中
            var updatetime = movieDoc.QuerySelector("span.updatetime");var pubDate = DateTime.Now;
            if(updatetime!=null && !string.IsNullOrEmpty(updatetime.InnerHtml))
            {
                //內容帶有“釋出時間:”字樣,replace成""之後再去轉換,轉換失敗不影響流程
                DateTime.TryParse(updatetime.InnerHtml.Replace("釋出時間:",""), out pubDate);
            }


            var movieInfo = new MovieInfo()
            {
                //InnerHtml中可能還包含font標籤,做多一個Replace
                MovieName = a.InnerHtml.Replace("<font color=\"#0c9000\">","").Replace("<font color=\"    #0c9000\">","").Replace("</font>",""),
                Dy2018OnlineUrl = onlineURL,
                MovieIntro = zoom != null ? WebUtility.HtmlEncode(zoom.InnerHtml) :"暫無介紹...",//可能沒有簡介,雖然好像不怎麼可能
                XunLeiDownLoadURLList = lstDownLoadURL != null ?
                lstDownLoadURL.Select(d => d.FirstElementChild.InnerHtml).ToList() :null,//可能沒有下載連結
                PubDate = pubDate,
            };
            return movieInfo;
        }

HTTPHelper

這邊有個小坑,dy2018網頁編碼格式是GB2312,.NET Core預設不支援GB2312,使用Encoding.GetEncoding(“GB2312”)的時候會丟擲異常。

解決方案是手動安裝System.Text.Encoding.CodePages包(Install-Package System.Text.Encoding.CodePages),

然後在Starup.cs的Configure方法中加入Encoding.RegisterProvider(CodePagesEncodingProvider.Instance),接著就可以正常使用Encoding.GetEncoding(“GB2312”)了。

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

namespace Dy2018Crawler
{
    public class HTTPHelper
    {

        public static HttpClient Client { get; } = new HttpClient();

        public static string GetHTMLByURL(string url)
        {
            try
            {
                System.Net.WebRequest wRequest = System.Net.WebRequest.Create(url);
                wRequest.ContentType = "text/html; charset=gb2312";

                wRequest.Method = "get";
                wRequest.UseDefaultCredentials = true;
                // Get the response instance.
                var task = wRequest.GetResponseAsync();
                System.Net.WebResponse wResp = task.Result;
                System.IO.Stream respStream = wResp.GetResponseStream();
                //dy2018這個網站編碼方式是GB2312,
                using (System.IO.StreamReader reader =new System.IO.StreamReader(respStream, Encoding.GetEncoding("GB2312")))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return string.Empty;
            }
        }

    }


}

定時任務的實現

Pomelo.AspNetCore.TimedJob是一個.NET Core實現的定時任務job庫,支援毫秒級定時任務、從資料庫讀取定時配置、同步非同步定時任務等功能。

由.NET Core社群大神兼前微軟MVPAmamiyaYuuko(入職微軟之後就卸任MVP…)開發維護,不過好像沒有開源,回頭問下看看能不能開源掉。

Startup.cs相關程式碼

我這邊使用的話,首先肯定是先安裝對應的包:Install-Package Pomelo.AspNetCore.TimedJob -Pre

然後在Startup.cs的ConfigureServices函式裡面新增Service,在Configure函式裡面Use一下。

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();
            //Add TimedJob services
            services.AddTimedJob();
        }

         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            //使用TimedJob
            app.UseTimedJob();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }

Job相關程式碼

接著新建一個類,明明為XXXJob.cs,引用名稱空間using Pomelo.AspNetCore.TimedJob,XXXJob繼承於Job,新增以下程式碼。

    public class AutoGetMovieListJob:Job
    {

        // Begin 起始時間;Interval執行時間間隔,單位是毫秒,建議使用以下格式,此處為3小時;SkipWhileExecuting是否等待上一個執行完成,true為等待;
        [Invoke(Begin = "2016-11-29 22:10", Interval = 1000 * 3600*3, SkipWhileExecuting =true)]
        public void Run()
        {
             //Job要執行的邏輯程式碼

            //LogHelper.Info("Start crawling");
            //AddToLatestMovieList(100);
            //AddToHotMovieList();
            //LogHelper.Info("Finish crawling");
        }
   }

專案釋出相關

新增runtimes節點

使用VS2015新建的模板工程,project.json配置預設是沒有runtimes節點的.

我們想要釋出到非Windows平臺的時候,需要手動配置一下此節點以便生成。


    "runtimes": {
    "win7-x64": {},
    "win7-x86": {},
    "osx.10.10-x64": {},
    "osx.10.11-x64": {},
    "ubuntu.14.04-x64": {}
  }

刪除/註釋scripts節點

生成時會呼叫node.js指令碼構建前端程式碼,這個不能確保每個環境都有bower存在…註釋完事。


    //"scripts": {
    //  "prepublish": [ "bower install", "dotnet bundle" ],
    //  "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
    //},

刪除/註釋dependencies節點裡面的type

"dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.1.0"
      //"type": "platform"
    },

開發編譯釋出

//還原各種包檔案
dotnet restore;

//釋出到C:\code\website\Dy2018Crawler資料夾
dotnet publish -r ubuntu.14.04-x64 -c Release -o "C:\code\website\Dy2018Crawler";

最後,照舊開源……以上程式碼都在下面找到:

PS:回頭寫個爬片大家滋持不啊…

相關推薦

手把手.NET Core爬蟲

寫在前面 自從上一個專案58HouseSearch從.NET遷移到.NET core之後,磕磕碰碰磨蹭了一個月才正式上線到新版本。 然後最近又開了個新坑,搞了個Dy2018Crawler用來爬dy2018電影天堂上面的電影資源。這裡也藉機簡單介紹一下如何基於

教女朋友學python系列--手把手Python3進行網路爬蟲

手把手教你用Python3進行網路爬蟲 2018/6/11 星期一 整理 執行的環境: win10 x64 安裝了anaconda3,基於Python3環境執行 使用Pycharm程式設計 1. 前期工作 安裝

手把手node擼一個簡易的handless爬蟲cli工具

眾所周知,node功能很強大,為前端提供了更多的可能。今天,就跟大家分享一下我是如何用node寫一個handless爬蟲的。原文連結leeing.site/2018/10/17/… 用到的工具 puppeteer commander inquirer chal

手把手C++ ACM自動刷題神器(衝入HDU首頁)

少年,作為苦練ACM,通宵刷題的你 是不是想著有一天能夠榮登各大OJ榜首,俯瞰芸芸眾生,唔....要做到這件事情可是需要一定天賦的哦! 博主本身也搞過一段時間的acm,對刷題深有感觸,不信可以去看我部落格的acm題解(哈哈)。 不過,先給各位辛苦刷題的ACMer賠個不是,畢

手把手jumpserver搭建堡壘機!

ict 添加用戶 以及 這一 用戶名 端口 cal cti tom 首先,jumpserver是什麽呢? Jumpserver 是一款由Python編寫開源的跳板機(堡壘機)系統,實現了跳板機應有的功能。基於ssh協議來管理,客戶端無需安裝agent。 特點: 完全開源,G

手把手ngrx管理Angular狀態

cli emit spl 工作 準備就緒 優雅 spa 現在 改字體 本文將與你一起探討如何用不可變數據儲存的方式進行Angular應用的狀態管理 :ngrx/store——Angular的響應式Redux。本文將會完成一個小型簡單的Angular應用,最終代碼可以在這裏下

手把手EST進行固件降級

希捷固件降級範例型號: ST3600057SS 固件版本 EN03 為DELL EQL存儲設備用的硬盤固件,像這類使用非標準扇區字節數,又或者關閉硬盤寫入緩存的情況,是不能在普通PC上使用,或者表速度很慢,所以我們進行降級固件,讓其能在普通PC上正常使用。本文出自 “EST硬盤之家” 博客,請務必保留此出處

手把手npm發布一個包,詳細教程

文件夾 模塊 .com png keyword tor 速度慢 index bsp 我們已經實現了路由的自動化構建,但是我們可以看到,一大串代碼懟在裏面。當然你也可以說,把它封裝在一個JS文件裏面,然後使用require(‘./autoRoute.js‘)給引入進來,那也行

手把手webpack3搭建react項目(開發環境和生產環境)(一)

stc reac config nod top llb cor git history 開發環境和生產環境整個配置源碼在github上,源碼地址:github-webpack-react 如果覺得有幫助,點個Star謝謝!! (一)是開發環境,(二)是生產環境。 一、首

手把手Rancher創建產品質量數據庫設置

max 模板 此外 以及 參考 -o 努力 otto 引入 目標:在本文中,我們將介紹如何運行一個分布式產品質量數據庫設置,它由Rancher進行管理,並且保證持久性。為了部署有狀態的分布式Cassandra數據庫,我們將使用Stateful Sets (有狀態集)以及Ra

手把手Python實踐深度學習|深度學習視頻教程

視頻 ref ati pan 人工神經網絡 com 深度學習 encoder auto 手把手教你用Python實踐深度學習網盤地址:https://pan.baidu.com/s/1mkoC9ELXDglvTNN_xPUWlQ 提取碼: zgpy備用地址(騰訊微雲):ht

手把手 | 幾行Python和消費資料做客戶細分

    細分客戶群是向客戶提供個性化體驗的關鍵。它可以提供關於客戶行為、習慣與偏好的相關資訊,幫助企業提供量身定製的營銷活動從而改善客戶體驗。在業界人們往往把他吹噓成提高收入的萬能藥,但實際上這個操作並不複雜,本文就將帶你用簡單的程式碼實現這一專案。 客戶

手把手 幾行Python和消費資料做客戶細分

  細分客戶群是向客戶提供個性化體驗的關鍵。它可以提供關於客戶行為、習慣與偏好的相關資訊,幫助企業提供量身定製的營銷活動從而改善客戶體驗。在業界人們往往把他吹噓成提高收入的萬能藥,但實際上這個操作並不複雜,本文就將帶你用簡單的程式碼實現這一專案。 我們需要建立什麼?

手把手Ucos

Ucos作業系統的學習   實時作業系統: 任務切換,排程 分式作業系統   不可剝奪型核心 Ucosii嵌入式實時作業系統的原始碼分為三部分:與硬體無關的核心程式碼,與處理器有關的移植程式碼和使用者配置檔案。   Ucos最多支援64個任務,

.net core 後端—— c++外的另一種選擇?

https://blog.csdn.net/kenkao/article/details/71249138 用.net core 寫後端—— c++外的另一種選擇? 2017年05月06日 10:40:48 獨孤殘雲 閱讀數:8283 本文原創版權歸 騰訊GAD&nb

手把手npm釋出包

一、釋出一個新包 第一步:進入要釋出的專案根目錄,初始化為npm包: npm init 依次按提示填入包名、版本、描述、github地址、關鍵字、license等 這步完成之後會生成一個package.json檔案,上面輸入的這些資訊可以在該檔案中修改 注意:如果你的包引用

獨家 | 手把手Python進行Web抓取(附程式碼)

作為一名資料科學家,我在工作中所做的第一件事就是網路資料採集。使用程式碼從網站收集資料,當時對我來說是一個完全陌生的概念,但它是最合理、最容易獲取的資料來源之一。經過幾次嘗試,網路抓取已經成為我的第二天性,也是我幾乎每天使用的技能之一。 在本教程中,我將介紹一個簡單的例子,說明如何抓取一個網站,

【Python量化】手把手python做股票分析入門

內容來自:微信公眾號:python金融量化 關注可瞭解更多的金融與Python乾貨。 目前,獲取股票資料的渠道有很多,而且基本上是免費的,比如,行情軟體有同花順、東方財富等,入口網站有新浪財經、騰訊財經、和訊網等。Python也有不少免費的開源api可以獲取交易行情資料,如pandas自

手把手Delphi實現硬體版hello world程式設計控制點亮電燈泡

之前我們已經給廣大愛好者或程式設計師朋友們,帶來了硬體版的或者說物聯網版本的Hello World C++Builder版的程式原始碼和教學資料,讓大家對硬體控制帶來一個嶄新的認識。今天我們再出一套兄弟版本Delphi程式語言的教程與例項原始碼。 Delphi的開發與C++B

人工智慧應用-手把手Python硬體程式設計實現開啟或關閉電燈泡

之前我們已經給廣大愛好者或程式設計師朋友們,帶來了硬體版的或者說物聯網版本的Hello World C++Builder版、Delphi、Visual Basic.Net等的程式原始碼和教學資料,讓大家對硬體控制帶來一個嶄新的認識。有不少讀者使用者,建議我們出一套Python