黨 佩,閻光偉
(華北電力大學(xué) 控制與計(jì)算機(jī)工程學(xué)院,北京 102206)
電力生產(chǎn)是把各種一次能源,包括化石燃料(煤炭、石油、天然氣)、可再生能源(水能、風(fēng)能、太陽(yáng)能、潮汐能、地?zé)崮芎蜕镔|(zhì)能等)以及核能轉(zhuǎn)換成電能,并輸送和分配到用戶。一直以來(lái),電力工業(yè)都是世界各國(guó)發(fā)展經(jīng)濟(jì)戰(zhàn)略的重中之重,作為一項(xiàng)基礎(chǔ)能源產(chǎn)業(yè),它的發(fā)展關(guān)系到國(guó)計(jì)民生的發(fā)展,是國(guó)民經(jīng)濟(jì)發(fā)展中最重要的一部分[1-2]。然而,近年來(lái),電力行業(yè)安全事故依舊時(shí)有發(fā)生,即使短短幾秒鐘的一次大停電事故,它所帶來(lái)的影響也不亞于一場(chǎng)大地震帶來(lái)的破壞性[3-4]。因此,采取有效的手段來(lái)獲取并管理電力安全事故信息,仔細(xì)分析所有的電力事故發(fā)生的原因,充分發(fā)掘事故信息數(shù)據(jù)的內(nèi)在價(jià)值,為安全事故的預(yù)防工作提供參考信息,改善工作中存在的漏洞,才能避免大型事故的再次發(fā)生。
互聯(lián)網(wǎng)的快速發(fā)展,使得人們可以應(yīng)用互聯(lián)網(wǎng)便捷、高效地獲取所需的各種信息。但是,互聯(lián)網(wǎng)上的網(wǎng)絡(luò)數(shù)據(jù)量以驚人的速度呈幾何級(jí)數(shù)增長(zhǎng)[5],利用人工獲取費(fèi)時(shí)費(fèi)力,而網(wǎng)絡(luò)爬蟲(chóng)技術(shù)[6-7]是一種快速獲取電力事故信息的全新方式。通過(guò)利用WebMagic增量爬取技術(shù),實(shí)現(xiàn)了自動(dòng)爬取電力安全管理網(wǎng)站中的電力事故信息,并將爬取所獲得的結(jié)果存儲(chǔ)到數(shù)據(jù)庫(kù)中。
WebMagic是應(yīng)用Java語(yǔ)言實(shí)現(xiàn)的Web爬蟲(chóng),參考了Scrapy的設(shè)計(jì)原理。Scrapy是一種使用Python語(yǔ)言開(kāi)發(fā),用于快速、高層次的屏幕抓取和Web站點(diǎn)抓取,同時(shí)能夠從抓取的頁(yè)面中提取出結(jié)構(gòu)化數(shù)據(jù)的框架[8]。通過(guò)使用最成熟的一些Java開(kāi)發(fā)工具,如HttpClient、Jsoup等完成具體的實(shí)現(xiàn)。
WebMagic是由Downloader、PageProcessor、Scheduler、Pipeline四個(gè)組件構(gòu)成的[9],其中Downloader完成從互聯(lián)網(wǎng)上下載頁(yè)面的功能;PageProcessor主要是對(duì)所要下載的頁(yè)面進(jìn)行解析,從中抽取出有用的信息,同時(shí)發(fā)現(xiàn)一些相關(guān)的新的鏈接;Scheduler負(fù)責(zé)管理所有待抓取的URL,并完成去重的功能;而處理抽取的結(jié)果,包括對(duì)結(jié)果進(jìn)行計(jì)算、將結(jié)果持久化到文件或數(shù)據(jù)庫(kù)等操作由Pipeline組件完成。WebMagic邏輯的核心組件是Spider,Spider可以看作一個(gè)大容器,它將其余四個(gè)組件管理起來(lái),實(shí)現(xiàn)組件之間的相互交互,以及流程化的執(zhí)行。
圖1為WebMagic總體架構(gòu)。
圖1 WebMagic總體架構(gòu)
如圖1所示,Request既實(shí)現(xiàn)了PageProcessor與Downloader之間的交互,又實(shí)現(xiàn)了PageProcessor對(duì)Downloader的控制。Request通過(guò)對(duì)URL地址進(jìn)行封裝,保證一個(gè)Request請(qǐng)求對(duì)應(yīng)一個(gè)URL地址。
通過(guò)Downloader組件下載得到一個(gè)頁(yè)面,該頁(yè)面可能是不同格式的文件,如包括HTML格式、JSON格式或其他文本格式等,Page則用來(lái)表示內(nèi)容,提供抽取信息和保存結(jié)果等功能,因此,Page是實(shí)現(xiàn)WebMagic抽取功能的核心對(duì)象。
PageProcessor將處理得到的結(jié)果交給ResultItems對(duì)象保存,Pipeline組件需要使用這些結(jié)果時(shí),由ResultItems對(duì)象提交給它使用。
Maven是一種專業(yè)的工具,用于構(gòu)建和管理Java相關(guān)項(xiàng)目[10],應(yīng)用Maven管理的Java項(xiàng)目都有著相同的項(xiàng)目結(jié)構(gòu),即:采用統(tǒng)一的標(biāo)準(zhǔn)管理java的目錄結(jié)構(gòu),src/main/java目錄下存放所有的java代碼,而src/test/java目錄下存放所有的測(cè)試代碼。同時(shí),Maven統(tǒng)一維護(hù)所有的jar包[11],所有需要的jar包都被放在一個(gè)本地“倉(cāng)庫(kù)”里,當(dāng)某個(gè)項(xiàng)目需要用到某一個(gè)jar包的時(shí)候,只需給出當(dāng)前所需jar包的名稱和版本號(hào),以此實(shí)現(xiàn)jar包的共享;當(dāng)本地“倉(cāng)庫(kù)”里找不到所需jar包時(shí),根據(jù)所提供的名稱和版本號(hào),Maven會(huì)自動(dòng)從遠(yuǎn)程倉(cāng)庫(kù)中下載這個(gè)jar包,所有的配置只需在pom.xml的配置文件中完成。
文中采用WebMagic爬蟲(chóng)技術(shù),以電力安全管理網(wǎng)(http://www.safehoo.com/NewsSpecial/Electric/)為例,獲取當(dāng)前網(wǎng)站中全部與電力事故相關(guān)的新聞,包括當(dāng)前頁(yè)面的URL地址,新聞的標(biāo)題,以及新聞的內(nèi)容,并將爬取所得的結(jié)果存儲(chǔ)進(jìn)數(shù)據(jù)庫(kù)。實(shí)驗(yàn)具體的操作流程如圖2所示。
圖2 信息爬取操作流程
為了應(yīng)用WebMagic進(jìn)行爬蟲(chóng)操作,首先需要借助Maven進(jìn)行依賴管理,因此在項(xiàng)目的pom.xml配置文件中添加對(duì)象的依賴即可,如下所示:
2.2.1 列表頁(yè)面及文章頁(yè)面的URL確定
電力安全管理網(wǎng)站是以列表頁(yè)分頁(yè)的形式顯示電力事故信息的,因此,需要通過(guò)遍歷這些分頁(yè)找到所有的目標(biāo)頁(yè)面。
通過(guò)分析頁(yè)面URL,列表頁(yè)的格式是“http://www.safehoo.com/NewsSpecial/Electric/List_1.shtml”,其中List_1中的“1”是可變的頁(yè)數(shù)。為了動(dòng)態(tài)獲取當(dāng)前網(wǎng)站總的分頁(yè)數(shù),進(jìn)行如下操作:首先,經(jīng)過(guò)分析,當(dāng)前頁(yè)面在最下面的分頁(yè)導(dǎo)航條中,除了提供點(diǎn)擊進(jìn)行跳轉(zhuǎn)到首頁(yè),當(dāng)前頁(yè)的上一頁(yè),當(dāng)前頁(yè)的下一頁(yè)和尾頁(yè)的功能以外,同時(shí)顯示當(dāng)前網(wǎng)站總的數(shù)據(jù)量和每頁(yè)可以顯示多少條數(shù)據(jù)的信息的功能。因此,通過(guò)使用HttpURLConnection類,將當(dāng)前的頁(yè)面下載下來(lái),下載的結(jié)果即為當(dāng)前頁(yè)面的HTML編碼,將該結(jié)果存儲(chǔ)到字節(jié)流當(dāng)中,利用正則表達(dá)式,匹配出分頁(yè)導(dǎo)航條中顯示的當(dāng)前網(wǎng)站總的數(shù)據(jù)量和每頁(yè)顯示多少條數(shù)據(jù)的信息,并將匹配結(jié)果從字節(jié)流當(dāng)中取出,利用這兩個(gè)數(shù)據(jù)進(jìn)行如下判斷:
假設(shè)m表示當(dāng)前網(wǎng)站總的數(shù)據(jù)量,n表示每頁(yè)可以顯示數(shù)據(jù)的條數(shù),p表示當(dāng)前網(wǎng)站的總頁(yè)數(shù),則m%n≠0,則p=m/n+1;反之,m%n=0,p=m/n。其中,%表示求余運(yùn)算,/表示除運(yùn)算。
以此,可以獲取到當(dāng)前網(wǎng)站的總頁(yè)數(shù),以總頁(yè)數(shù)為循環(huán)條件,依次放入“http://www.safehoo.com/NewsSpecial/Electric/List_*.shtml”這個(gè)URL地址中List_*中的“*”的位置中,即為列表頁(yè)的URL。
而文章頁(yè)的格式為http://www.safehoo.com/News/News/China/201103/173316.shtml,其中“2011 03/173316”是可變的字符串。
2.2.2 定義實(shí)體類,封裝爬取內(nèi)容,并解析HTML
當(dāng)確定了列表頁(yè)和文章頁(yè)的URL地址,接下來(lái)要先實(shí)現(xiàn)對(duì)爬取的內(nèi)容進(jìn)行確定,解析當(dāng)前網(wǎng)頁(yè)的HTML,獲取所需的信息。圖3所示為打開(kāi)瀏覽器的開(kāi)發(fā)者工具后,當(dāng)前網(wǎng)站的HTML結(jié)構(gòu)。
圖3 電力安全管理網(wǎng)HTML結(jié)構(gòu)
其中新聞標(biāo)題存在于div的class屬性為c_title_text標(biāo)簽h1下,通過(guò)XPath選擇語(yǔ)句//div[@class='c_title_text']/h1/text(),即可獲得當(dāng)前的新聞標(biāo)題。同理,可以分析出新聞內(nèi)容的選擇語(yǔ)句為//div[@class='c_content_text']/p/text()。新聞的URL利用正則表達(dá)式[12]獲取,選擇語(yǔ)句為http://www.safehoo.com/News/News/China/\d+/\w*\.shtml。
WebMagic可以使用注解的方式將抽取規(guī)則作用到某個(gè)指定的字段上,以此來(lái)表示依據(jù)這個(gè)抽取規(guī)則抽取的結(jié)果均保存到這個(gè)字段中。WebMagic中提供了兩個(gè)注解,分別是@ExtractBy注解和@ExtractByUrl注解??梢允褂肅SS選擇器、正則表達(dá)式、XPath和JsonPath等方式定義注解表示規(guī)則,需要注意,@ExtractByUrl注解除正則表達(dá)式定義的規(guī)則以外,其他方式均不支持。
利用這兩個(gè)注解,當(dāng)前所要爬取的信息實(shí)體類定義如圖4所示。
圖4 爬取信息的實(shí)體類定義
其中@TargetUrl注解表示最終要抓取的URL,也就是2.2.1節(jié)分析所得文章頁(yè)的URL,最終想要的數(shù)據(jù)內(nèi)容都來(lái)自與注解中第一的規(guī)則匹配的信息,即:http://www.safehoo.com/News/News/China/\d+/\w+.shtml;而@HelpUrl則是為了幫助找到最終URL過(guò)程中需要訪問(wèn)的頁(yè)面,也就是2.2.1節(jié)分析所得的列表頁(yè)URL,即為匹配這個(gè)規(guī)則(http://www.safehoo.com/News/News/China/**)的所有頁(yè)面。
2.2.3 定制PageProcessor
爬蟲(chóng)信息的配置、頁(yè)面元素抽取規(guī)則的制定以及新鏈接的發(fā)現(xiàn)是定制PageProcessor過(guò)程中的三個(gè)主要部分。其中包括對(duì)編碼信息、每次抓取間隔的時(shí)間、超時(shí)時(shí)間、重試次數(shù)等信息的配置,以及一些模擬的參數(shù),比如User Agent、cookie,以及代理的設(shè)置,是爬蟲(chóng)信息配置階段需要完成的功能。本次實(shí)驗(yàn)中,設(shè)置重試次數(shù)為2,超時(shí)時(shí)間為1 000 s,開(kāi)啟了2個(gè)線程。表1為爬蟲(chóng)配置信息相關(guān)的方法。
表1 爬蟲(chóng)配置信息相關(guān)的方法
頁(yè)面元素的抽取,WebMagic中主要提供了XPath、正則表達(dá)式和CSS選擇器三種抽取方式。實(shí)驗(yàn)中,關(guān)于新聞標(biāo)題和新聞內(nèi)容的抽取,選擇了XPath的抽取方式[13];而當(dāng)前新聞頁(yè)面的URL的抽取,選擇了正則表達(dá)式的方式,之所以選擇不同的抽取方式,因?yàn)椴煌男畔⒊槿』诓煌淖⒔狻?/p>
新鏈接的發(fā)現(xiàn),是指當(dāng)前所要爬取的一個(gè)站點(diǎn)的頁(yè)面有很多,不可能在開(kāi)始的時(shí)候?qū)⑷宽?yè)面列舉出來(lái),因此需要爬蟲(chóng)實(shí)現(xiàn)自動(dòng)發(fā)現(xiàn)后續(xù)相關(guān)鏈接的功能,如下代碼,為本實(shí)驗(yàn)中后續(xù)代碼發(fā)現(xiàn)的部分操作。
page.addTargetRequests(page.getHtml().links().regex("http://www.safehoo.com/News/News/China/\d+/\w*\.shtml").all());
其中,page.getHtml().links().regex("http://www.safhoo.com/News/News/China/\d+/\w*\.shtml").all()用于獲取所有滿足“( http://www.safehoo.com/News/News/China/\d+/\w*\.sh-tml)”這個(gè)正則表達(dá)式的鏈接,而將所有滿足條件的鏈接加入到待抓取的隊(duì)列中去,以此實(shí)現(xiàn)發(fā)現(xiàn)后續(xù)新的鏈接的功能由page.addTargetRequests()方法完成。
2.2.4 編寫(xiě)Pipeline,將爬取到的數(shù)據(jù)保存到數(shù)據(jù)庫(kù)
Pipeline,是WebMagic用于保存抽取結(jié)果的組件,其實(shí)質(zhì)是將PageProcessor組件抽取得到的結(jié)果繼續(xù)進(jìn)行后續(xù)處理。而之所以采用了兩個(gè)組件進(jìn)行數(shù)據(jù)處理,是基于以下兩個(gè)原因:第一,實(shí)現(xiàn)模塊分離,分別將爬蟲(chóng)的兩個(gè)階段“頁(yè)面信息的抽取”和“數(shù)據(jù)的持久化”交由兩個(gè)不同的組件完成,既可以保證代碼結(jié)構(gòu)清楚,又可以實(shí)現(xiàn)處理過(guò)程分開(kāi)進(jìn)行,完成在獨(dú)立的線程甚至于不同的機(jī)器上執(zhí)行處理過(guò)程的功能;第二,由于Pipeline組件實(shí)現(xiàn)功能相對(duì)固定,保存結(jié)果到控制臺(tái)或者數(shù)據(jù)庫(kù)中,這些操作對(duì)于所有的頁(yè)面都是一樣的,因此更容易做成通用組件,而頁(yè)面的抽取方式變化很多,頁(yè)面的結(jié)構(gòu)也不盡相同,因此抽取規(guī)則需要根據(jù)每個(gè)網(wǎng)頁(yè)特別定制,不易做成通用組件。
本實(shí)驗(yàn)實(shí)現(xiàn)了將結(jié)果輸出到控制臺(tái)并保存到數(shù)據(jù)庫(kù)中。應(yīng)用MySQL數(shù)據(jù)庫(kù)保存抽取的結(jié)果,數(shù)據(jù)持久化層框架[14]采用JPA(Java persistence API),具體實(shí)現(xiàn)過(guò)程為:首先,業(yè)務(wù)邏輯層需要實(shí)現(xiàn)PageModel Pipeline接口,然后將接口中的抽象方法process(ResultItems resultItems,Task task)重寫(xiě),其中參數(shù)ResultItems類用來(lái)保存抽取結(jié)果,它本身是鍵值對(duì)的結(jié)構(gòu),可以通過(guò)ResultItems.get(key)獲取在page.putField(key,value)中保存的數(shù)據(jù)。該方法中添加輸出到控制臺(tái)的語(yǔ)句,并且調(diào)用數(shù)據(jù)持久化層保存數(shù)據(jù)進(jìn)數(shù)據(jù)庫(kù)的方法即可。圖5所示為保存到數(shù)據(jù)庫(kù)中的結(jié)果。
圖5 數(shù)據(jù)庫(kù)存儲(chǔ)結(jié)果
通過(guò)對(duì)WebMagic爬蟲(chóng)技術(shù)的研究,應(yīng)用Maven技術(shù)管理java項(xiàng)目,實(shí)現(xiàn)了對(duì)電力安全管理網(wǎng)站上電力事故信息的爬取和存儲(chǔ)。在實(shí)驗(yàn)過(guò)程中,通過(guò)對(duì)網(wǎng)頁(yè)結(jié)構(gòu)的分析,分別對(duì)所要爬取的字段采用XPath和正則表達(dá)式的方式指定抽取規(guī)則,定制PageProcessor組件,實(shí)現(xiàn)信息的順利爬取,同時(shí),應(yīng)用Pipeline組件,實(shí)現(xiàn)爬取數(shù)據(jù)存儲(chǔ)入庫(kù)。應(yīng)用該模式,可以實(shí)現(xiàn)對(duì)其他相關(guān)電力網(wǎng)站事故信息的爬取,通過(guò)整理分析歷年事故信息,對(duì)每次事故發(fā)生原因高度重視,采取必要的措施加以解決和管理,避免大型事故的重復(fù)發(fā)生。只有遏制住電力生產(chǎn)安全事故的發(fā)生,才能創(chuàng)造出更好的經(jīng)濟(jì)效益。