新聞站群開發日志(一)—— 新聞抓取

1. 了解需求

公司負責運營的同事找到我,說需要搭建一個新聞站群,用于引入流量。每個站的新聞數據都去別的新聞站抓取,每天晚上10點更新數據,每個站還需要單獨配置SEO(首頁、頻道頁、詳情頁)、友情鏈接內容。

拆分需求

  • 新聞抓取,每個新聞站的抓取數據源都不一致,所以抓取我們需要靈活配置。
  • 每天定時,所以我們需要一個Windows 服務,定時完成抓取任務。
  • 新聞站群,意味著會有很多站,如果每個站單獨一個數據庫,那么后期程序維護工作將會很龐大,所以我們需要做到一個庫對應n個站

2. 功能實現

拆分需求后,接下來我們要挨個實現每個需求對應的功能。

新聞抓取

看到抓取時,首先想到的是HtmlAgilityPack,Github鏈接是https://github.com/zzzprojects/html-agility-pack,HtmlAgilityPack可以加載html,并且提供了函數SelectNodes,可以非常方便我們定位到需要抓取的DOM節點。下面看看這個函數的示例(http://html-agility-pack.net/select-nodes):

var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);

string name = htmlDoc.DocumentNode
    .SelectNodes("http://td/input")
    .First()
    .Attributes["value"].Value;'

這里需要重點關注的是SelectNodes的參數//td/input,這個參數名叫XPath,那么我們怎么取到一個網站某個節點的XPath呢,可以通過Chrome瀏覽器直接獲取。首先打開我們的目標網站:http://www.southcn.com/pc2016/yw/node_346416.htm,我們要抓取的是列表部分,如下圖:

需要抓取的數據

確定好目標后,我們可以通過Chrome直接復制出XPath,如下圖:
獲取XPath.gif

Copy完XPath之后,我們可以貼出來看看XPath://*[@id="content"]/div[1]/div[1]/div[1]/div/h3/a
然后在Chrome的Console里面輸入:

$x('//*[@id="content"]/div[1]/div[1]/div[1]/div/h3/a')

我們看看能得到什么:

抓取單個a標簽

只有一個a鏈接,可是我們要獲取的是整個列表,這與我們的需求不符,那么如何理解這句XPath代表的含義呢,我們需要查看下XPath的語法:http://www.w3school.com.cn/xpath/xpath_syntax.asp
了解語法后,我們了解到XPath路勁(//[@id="content"]/div[1]/div[1]/div[1]/div/h3/a)指定了具體的某個div,我們只要修改下就好:'//[@id="content"]/div[1]/div[1]/div/div/h3/a',重新在Console里面輸入:

$x('//*[@id="content"]/div[1]/div[1]/div/div/h3/a')

這時候得到的就是整個列表的a鏈接了:

抓取列表a標簽

拿到詳情頁的鏈接后,接下來我們要抓取正文內容,打開詳情頁:http://news.southcn.com/china/content/2017-12/26/content_179881431.htm
正文內容

和之前列表一樣,獲取這幾個內容的XPath

  • 標題://*[@id="article_title"]
  • 時間://*[@id="pubtime_baidu"]
  • 來源://*[@id="source_baidu"]
  • 正文://*[@id="content"]
    ok,現在我們可以抓取新聞了。

問題點匯總

抓取思路沒有問題,而在實際抓取的過程中總是會遇到一些細節問題,這里匯總下

HtmlAgilityPack

HtmlAgilityPack 提供了一個Load函數,可以直接加載網頁:

var url = "http://html-agility-pack.net/";
var web = new HtmlWeb();
var doc = web.Load(url);

但是實際使用中
我們發現很多網頁加載下來后,竟然是亂碼,而導致亂碼的原因是不同的網站,采用的編碼不一樣,而Load函數并沒有設置編碼的地方……
所以果斷放棄Load,自己寫代碼加載網頁Html:

private string GetHtml(string url,string encoding)
        {
            using (var client = new WebClient())
            {
                client.Encoding = Encoding.GetEncoding(encoding);
                var html = client.DownloadString(url);
                return html;
            }
        }

同一個站點的XPath也會不一樣

很多網站的新聞詳情頁會采用不同的模板來顯示,比如說視頻+正文、圖片幻燈片+正文、正文等不同的組合方式。而這個時候要正確抓取數據,就需要同時記錄多個XPath,做好非空判斷,挨次抓取。

正文中的腳本處理

有些網站會在正文中嵌入廣告腳本,而這個時候抓取這些腳本顯然對我們沒什么幫助,所以要對正文內容過濾下,去除所有的腳本:

            var articleContent = contentDoc.InnerHtml;
            //移除正文中的script腳本
            Regex rRemScript = new Regex(@"<script[^>]*>[\s\S]*?</script>");
            articleContent = rRemScript.Replace(articleContent, "");
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。