【scrapy爬蟲】crawl自動化模板爬取網易新聞

手動反爬蟲:原博地址

 知識梳理不易,請尊重勞動成果,文章僅發佈在CSDN網站上,在其他網站看到該博文均屬於未經作者授權的惡意爬取信息

如若轉載,請標明出處,謝謝!

1. 新建項目

在命令行窗口下輸入scrapy startproject news,如下
在這裏插入圖片描述
然後就自動創建了相應的文件,如下
在這裏插入圖片描述
關於每一個文件的作用,上一個博客上有詳細介紹,可以回頭看一下

2. 修改itmes.py文件

打開scrapy框架自動創建的items.py文件,如下
在這裏插入圖片描述
編寫裏面的代碼,確定我要獲取的信息,比如線程,新聞標題,url,時間,來源,來源的url,新聞的內容等

import scrapy


class NewsItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    news_thread = scrapy.Field()
    news_title = scrapy.Field()
    news_url = scrapy.Field()
    news_time = scrapy.Field()
    news_source = scrapy.Field()
    source_url = scrapy.Field()
    news_body = scrapy.Field()

3. 定義spider,創建一個爬蟲模板

3.1 創建crawl爬蟲模板

在命令行窗口下面 創建一個crawl爬蟲模板,指令執行會在spider文件夾生成一個news163.py文件

注意: 在文件的根目錄下面,指令檢查別輸入錯誤,-t 表示使用後面的crawl模板,news163爲爬蟲文件名稱,最後的news.163.com爲網易新聞域名
在這裏插入圖片描述
然後看一下這個‘crawl’模板和一般的模板有什麼區別,多了鏈接提取器還有一些爬蟲規則,這樣就有利於我們做一些深度信息的自動化爬取
在這裏插入圖片描述

3.2 xpath選擇器

支持xpath和css,其中css選擇器之前的爬蟲案例中介紹過了,這裏是補充xpath的操作,xpath語法如下

① 手寫輸入的:

/html/head/title 定位標題

/html/head/title/text() 提取標題內容

//td (深度提取的話就是兩個/) 直接定位td標籤

//div[@class='mine'] 定義帶有mine屬性的div標籤

② 手動copy的:

直接定位某一具體位置的標籤信息,往往復制粘貼之後使用的是相對路徑,即//開頭,後面再接標籤相關信息,比如的內容copy之後,粘貼的內容爲://*[@id="js_top_news"]/div[2]/ul/li[2]/a
在這裏插入圖片描述

3.3. 分析網頁內容

在谷歌chrome瀏覽器下,打在網頁新聞的網站,選擇查看源代碼,確認我們可以獲取到itmes.py文件的內容(其實那裏面的要獲取的就是查看了網頁源代碼之後確定可以獲取的)

確認標題、時間、url、來源url和內容可以通過檢查和標籤對應上,比如正文部分
在這裏插入圖片描述

4. 修改spider下創建的爬蟲文件

4.1 導入包

打開創建的爬蟲模板,進行代碼的編寫,除了導入系統自動創建的三個庫,我們還需要導入news.items(這裏就涉及到了包的概念了,最開始說的–init–.py文件存在說明這個文件夾就是一個包可以直接導入,不需要安裝)

注意:使用的類ExampleSpider一定要繼承自CrawlSpider,因爲最開始我們創建的就是一個‘crawl’的爬蟲模板,對應上

import scrapy
from news.items import NewsItem
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class New163Spider(CrawlSpider):
    name = 'new163'
    allowed_domains = ['new163.com']
    start_urls = ['http://new163.com/']

    rules = (
        Rule(LinkExtractor(allow=r'/18/04\d+/*'), callback='parse_news', follow=True),
    )

    def parse_item(self, response):
        item = {}
        #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        #item['name'] = response.xpath('//div[@id="name"]').get()
        #item['description'] = response.xpath('//div[@id="description"]').get()
        return item

Rule(LinkExtractor(allow=r’/18/04\d+/*’), callback=‘parse_news’, follow=True),其中第一個allow裏面是書寫正則表達式的(也是我們核心要輸入的內容),第二個是回調函數,第三個表示是否允許深入

4.2 正則表達式的簡單介紹

系統的介紹會在爬蟲專項裏面進行講解,這裏介紹一些基礎性的可以用在這個項目裏面的知識點,,正則表達式是由字符和操作符組成的,常見的語法如下圖
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述
記住一個:“.*?” 惰性匹配,匹配成功一次即可, 幾乎可以解決大部分的問題,還有一些需要我們自己動手編寫
對比新聞的標籤,如下
在這裏插入圖片描述
第一個新聞的url是:“https://news.163.com/20/0204/17/F4IDMINL000189FH.html”
第二個新聞的url是:“https://news.163.com/20/0204/07/F4HC2QS90001899O.html”

可以看出規律,因此正則表達式可以按照下面這樣寫

rules = (
        Rule(LinkExtractor(allow=r'https://news.163.com/20/0204/\d+/.*?html'), callback='parse_item', follow=True),
    )

然後在命令行窗口運行指令:scrapy crawl news163

輸出結果爲:請求返回200,代表請求成功
在這裏插入圖片描述

4.3 回調函數

parse_item是我們要設置的回調函數,先處理兩個較爲簡單的獲取內容,獲取thread(去掉網址的後五個字符的內容)和title(一般就是網頁源代碼的一個title標籤裏的內容),代碼設置如下

def parse_item(self, response):
    item = NewsItem()
    item['news_thread'] = response.url.strip().split("/")[-1][:-5]
    self.get_title(response,item)

    return item

def get_title(self,response,item):
    title = response.css('title::text').extract()
    if title:
        print("title:{}".format(title[0]))
        item['news_title'] = title[0]

保存後運行命令行窗口,輸出如下
在這裏插入圖片描述
然後再獲取時間,在頁面中選擇檢查,找到新聞時間對應的源代碼中的標籤信息,然後採用css選擇器,找到該標籤信息,如下
在這裏插入圖片描述
獲取新聞時間的代碼如下,time後面的內容就是屬於字符串處理的方式了,目的是爲了獲得正常格式的時間數據

self.get_time(response,item) #這個代碼要放在回調函數裏面

def get_time(self,response,item):
        time = response.css('div.post_time_source::text').extract()
        if time:
            print('time:{}'.format(time[0].strip().replace("來源","").replace('\u3000:',"")))
            item['news_time'] = time[0].strip().replace("來源","").replace('\u3000:',"")

輸出結果爲:
在這裏插入圖片描述
接下來獲取新聞來源,查看網頁源代碼,發現新聞來源是存儲id標籤下面,直接就可以進行標籤的查找鎖定(id唯一)
在這裏插入圖片描述
獲取新聞來源的代碼如下

self.get_source(response,item) #這個代碼要放在回調函數裏面

def get_source(self,response,item):
     source = response.css("ne_article_source::text").extract()
     if source:
         print("source:{}".format(source[0]))
         item['news_source'] = source[0]

獲取新聞原文URL的方式也是類似,這裏直接給出代碼(注意這裏不是獲取id標籤的文本內容了,而是屬性)

self.get_source_url(response,item)


def get_source_url(self,response,item):
    source_url = response.css("ne_article_source::attr(href)").extract()
    if source_url:
        print("source_url:{}".format(source_url[0]))
        item['source_url'] = source_url[0]

獲取新聞內容 ,也是直接給出參考代碼如下

self.get_text(response,item)

def get_text(self,response,item):
    text = response.css(".post_text p::text").extract()
    if text:
        print("text:{}".format(text))
        item['news_body'] = text

獲取新聞URL(最初的那個),也是直接給出參考代碼如下

self.get_url(response,item)

def get_url(self,response,item):
    url = response.url
    if url:
        item['news_url'] = url

至此news163.py的全部代碼編寫如下:

import scrapy
from news.items import NewsItem
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

#https://news.163.com/20/0205/06/F4JOHHEJ0001899O.html
#https://news.163.com/20/0205/08/F4JVQU6P000189FH.html
class News163Spider(CrawlSpider):
    name = 'news163'
    allowed_domains = ['news.163.com']
    start_urls = ['http://news.163.com/']

    rules = (
        Rule(LinkExtractor(allow=r'https://news.163.com/20/0205/\d+/.*?html'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        item = NewsItem()
        item['news_thread'] = response.url.strip().split("/")[-1][:-5]
        self.get_title(response,item)
        self.get_time(response,item)
        self.get_source(response,item)
        self.get_source_url(response,item)
        self.get_text(response,item)
        self.get_url(response,item)

        return item

    def get_url(self,response,item):
        url = response.url
        if url:
            item['news_url'] = url

    def get_text(self,response,item):
        text = response.css(".post_text p::text").extract()
        if text:
            print("text:{}".format(text))
            item['news_body'] = text

    def get_source_url(self,response,item):
        source_url = response.css("ne_article_source::attr(href)").extract()
        if source_url:
            #print("source_url:{}".format(source_url[0]))
            item['source_url'] = source_url[0]


    def get_source(self,response,item):
        source = response.css("ne_article_source::text").extract()
        if source:
            print("source:{}".format(source[0]))
            item['news_source'] = source[0]

    def get_time(self,response,item):
        time = response.css('div.post_time_source::text').extract()
        if time:
            print('time:{}'.format(time[0].strip().replace("來源","").replace('\u3000:',"")))
            item['news_time'] = time[0].strip().replace("來源","").replace('\u3000:',"")

    def get_title(self,response,item):
        title = response.css('title::text').extract()
        if title:
            print("title:{}".format(title[0]))
            item['news_title'] = title[0]

保存後,運行命令行輸出如下( 注意、注意、注意, 在調試的過程中不要頻繁的運行這個指令,否則會導致服務器無法訪問),只截取部分輸出結果
在這裏插入圖片描述

5. 修改pipeline文件下的內容

5.1 導入csv文件儲存包

要將數據儲存在本地,需要以一種格式作爲儲存的條件,逗號分隔符(csv)文件就可以滿足這種要求,而且也是現在主要存儲數據的工具

from scrapy.exporters import CsvItemExporter

5.2 定義進程函數

首先從初始化函數,包含了創建收集數據的文件和項目啓動器

def __init__(self):
	self.file = open('news_data.csv', 'wb')
	self.exporter = CsvItemExporter(self.file, encoding = 'utf-8')
	self.exporter.start_exporting()

其次,定義爬蟲結束器,進行項目的收尾工作,把進程和文件都關閉掉,防止內存溢出

def close_spider(self,spider):
	self.exporter.finish_exporting()
	self.file.close()

最後在處理函數裏面,開啓導入,最後返回Item

def process_item(self, item, spider):
	self.exporter.export_item(item)
    return item

至此,pipeline裏的代碼編寫就已經完成了,這時候就要在setting.py文件裏面進開啓pipeline通道,取消如下內容的註釋,如下
在這裏插入圖片描述
最後整個pipeline.py的文件代碼如下,注意檢查縮進的問題(Sublime編輯器裏面有講縮進全部轉換成爲tab格式的選項,確保縮進一致,而且還是要注意一下網頁編碼的問題,否則會出現亂碼的情況,encoding要根據爬取網頁的編碼格式設定)

from scrapy.exporters import CsvItemExporter

class NewsPipeline(object):

	def __init__(self):
		self.file = open('news_data.csv', 'wb')
		self.exporter = CsvItemExporter(self.file, encoding = 'gbk')
		self.exporter.start_exporting()

	def close_spider(self,spider):
		self.exporter.finish_exporting()
		self.file.close()

	def process_item(self, item, spider):
		self.exporter.export_item(item)
		return item

6. 運行結果

最後在命令行窗口,運行指令,在窗口界面出現爬取內容輸出的同時,在news文件夾下也自動生成了news_data.csv文件,如下
在這裏插入圖片描述
news_data.csv文件中數據樣式如下,至此整個利用Scrapy爬取網頁新聞的項目就全部完結了
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章