Python爬蟲框架:scrapy爬取高考派大學資料

嗨學程式設計發表於2019-10-07

1. 高考派大學資料----寫在前面

終於寫到了scrapy爬蟲框架了,這個框架可以說是python爬蟲框架裡面出鏡率最高的一個了,我們接下來重點研究一下它的使用規則。

安裝過程自己百度一下,就能找到3種以上的安裝手法,哪一個都可以安裝上 可以參考 scrapy-chs.readthedocs.io/zh_CN/0.24/… 官方說明進行安裝。

2. 高考派大學資料----建立scrapy專案

通用使用下面的命令,建立即可

scrapy startproject mySpider複製程式碼

完成之後,你的專案的目錄結構為 在這裡插入圖片描述 每個檔案對應的意思為

  • scrapy.cfg 專案的配置檔案

  • mySpider/ 根目錄

  • mySpider/items.py專案的目標檔案,規範資料格式,用來定義解析物件對應的屬性或欄位。

  • mySpider/pipelines.py專案的管道檔案,負責處理被spider提取出來的item。典型的處理有清理、 驗證及持久化(例如存取到資料庫)

  • mySpider/settings.py 專案的設定檔案

  • mySpider/spiders/ 爬蟲主目錄

  • middlewares.py Spider中介軟體是在引擎及Spider之間的特定鉤子(specific hook),處理spider的輸入(response)和輸出(items及requests)。 其提供了一個簡便的機制,通過插入自定義程式碼來擴充套件Scrapy功能。 本篇文章沒有涉及

高考派大學資料----建立Scrapy爬蟲

通過命令列進入到 mySpider/spiders/ 目錄,然後執行如下命令

scrapy genspider GaoKao "www.gaokaopai.com"

開啟mySpider/spiders/ 目錄裡面的 GaoKao,預設增加了 下列程式碼

import scrapy
 '''
遇到不懂的問題?Python學習交流群:821460695滿足你的需求,資料都已經上傳群檔案,可以自行下載!
'''
class GaoKaoSpider(scrapy.Spider):
    name = "GaoKao"
    allowed_domains = ["www.gaokaopai.com"]
    start_urls = ['http://www.gaokaopai.com/']
 
    def parse(self, response):
        pass複製程式碼

預設生成的程式碼,包含一個GaoKaoSpider的類,並且這個類是用scrapy.Spider繼承來的 而且預設實現了三個屬性和一個方法

  • name = "" 這個是爬蟲的名字,必須唯一,在不同的爬蟲需要定義不同的名字

  • allowed_domains = [] 域名範圍,限制爬蟲爬取當前域名下的網頁

  • start_urls =[] 爬取的URL元組/列表。爬蟲從這裡開始爬取資料,第一次爬取的頁面就是從這裡開始,其他的URL將會從這些起始的URL爬取的結果中生成

  • parse(self,response) 解析網頁的方法,每個初始URL完成下載後將呼叫,呼叫的時候傳入每一個初始URL返回的Response物件作為唯一引數,主要作用1、負責解析返回的網頁資料,response.body 2、生成下一頁的URL請求

高考派大學資料----第一個案例

我們要爬取的是高考派大學資料 資料為 www.gaokaopai.com/rank-index.… 在這裡插入圖片描述 頁面下部有一個載入更多,點選抓取連結 在這裡插入圖片描述 尷尬的事情發生了,竟然是一個POST請求,本打算實現一個GET的,這回程式碼量有點大了~ scrapy 模式是GET請求的,如果我們需要修改成POST,那麼需要重寫Spider類的start_requests(self) 方法,並且不再呼叫start_urls裡面的url了,所以,我們對程式碼進行一些修改。重寫程式碼之後,注意下面這段程式碼

request = FormRequest(self.start_url,headers=self.headers,formdata=form_data,callback=self.parse)複製程式碼
  • FormRequest 需要引入模組 from scrapy import FormRequest

  • self.start_url 寫上post請求的地址即可

  • formdata用來提交表單資料

  • callback呼叫網頁解析引數

  • 最後的 yield request 表示這個函式是一個生成器

import scrapy
from scrapy import FormRequest
import json
'''
遇到不懂的問題?Python學習交流群:821460695滿足你的需求,資料都已經上傳群檔案,可以自行下載!
'''
from items import MyspiderItem
class GaokaoSpider(scrapy.Spider):
    name = 'GaoKao'
    allowed_domains = ['gaokaopai.com']
    start_url = 'http://www.gaokaopai.com/rank-index.html'
​
    def __init__(self):
        self.headers = {
            "User-Agent":"自己找個UA",
            "X-Requested-With":"XMLHttpRequest"
        }
​
    # 需要重寫start_requests() 方法
    def start_requests(self):
        for page in range(0,7):
            form_data = {
                "otype": "4",
                "city":"",
                "start":str(25*page),
                "amount": "25"
            }
​
            request = FormRequest(self.start_url,headers=self.headers,formdata=form_data,callback=self.parse)
            yield request
​
    def parse(self, response):
        print(response.body)
        print(response.url)
        print(response.body_as_unicode())複製程式碼

我們在 def parse(self, response): 函式裡面,輸出一下網頁內容,這個地方,需要用到1個知識點是

獲取網頁內容 response.body response.body_as_unicode()

  • response.url獲取抓取的rul

  • response.body獲取網頁內容位元組型別

  • response.body_as_unicode()獲取網站內容字串型別

我們接下來就可以執行一下爬蟲程式了

在專案根目錄建立一個begin.py 檔案,裡面寫入如下程式碼 在這裡插入圖片描述

from scrapy import cmdline
cmdline.execute(("scrapy crawl GaoKao").split())複製程式碼

執行該檔案,記住在scrapy中的其他py檔案中,執行是不會顯示相應的結果的,每次測試的時候,都需要執行begin.py 當然,你可起一個其他的名字。

如果你不這麼幹的,那麼你只能 採用下面的操作,就是比較麻煩。

cd到爬蟲目錄裡執行scrapy crawl GaoKao--nolog命令
說明:scrapy crawl GaoKao(GaoKao表示爬蟲名稱) --nolog(--nolog表示不顯示日誌)複製程式碼

執行起來,就在控制檯列印資料了,測試方便,可以把上述程式碼中那個數字7,修改成2,有心人能看到我這個小文字

pycharm在執行過程中,會在控制檯列印很多紅色的字,沒事,那不是BUG 在這裡插入圖片描述 一定要在紅色的字中間找到黑色的字,黑色的字才是你列印出來的資料,如下,得到這樣的內容,就成功一大半了。 在這裡插入圖片描述

import scrapy
class MyspiderItem(scrapy.Item):
    # 學校名稱
    uni_name = scrapy.Field()
    uni_id = scrapy.Field()
    city_code = scrapy.Field()
    uni_type = scrapy.Field()
    slogo = scrapy.Field()
    # 錄取難度
    safehard = scrapy.Field()
    # 院校所在地
    rank = scrapy.Field()複製程式碼

然後在剛才的GaokaoSpider類中,繼續完善parse函式,通過判斷 response.headers["Content-Type"] 去確定本頁面是HTML格式,還是JSON格式。

        if(content_type.find("text/html")>0):
            # print(response.body_as_unicode())
            trs = response.xpath("//table[@id='results']//tr")[1:]
            for item in trs:
                school = MyspiderItem()
                rank = item.xpath("td[1]/span/text()").extract()[0]
                uni_name = item.xpath("td[2]/a/text()").extract()[0]
                safehard  = item.xpath("td[3]/text()").extract()[0]
                city_code = item.xpath("td[4]/text()").extract()[0]
                uni_type = item.xpath("td[6]/text()").extract()[0]
​
                school["uni_name"] = uni_name
                school["uni_id"] = ""
                school["city_code"] = city_code
                school["uni_type"] = uni_type
                school["slogo"] = ""
                school["rank"] = rank
                school["safehard"] = safehard
                yield school
​
​
        else:
            data = json.loads(response.body_as_unicode())
            data = data["data"]["ranks"] # 獲取資料
            
            for item in data:
                school = MyspiderItem()
                school["uni_name"] = item["uni_name"]
                school["uni_id"] = item["uni_id"]
                school["city_code"] = item["city_code"]
                school["uni_type"] = item["uni_type"]
                school["slogo"] = item["slogo"]
                school["rank"] = item["rank"]
                school["safehard"] = item["safehard"]
                # 將獲取的資料交給pipelines,pipelines在settings.py中定義
                yield school複製程式碼

parse() 方法的執行機制

  • 使用yield返回資料,不要使用return。這樣子parse就會被當做一個生成器。scarpy將parse生成的資料,逐一返回

  • 如果返回值是request則加入爬取佇列,如果是item型別,則交給pipeline出來,其他型別報錯

到這裡,如果想要資料準備的進入到 pipeline 中,你需要在setting.py中將配置開啟

    # See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
    ITEM_PIPELINES = {
       'mySpider.pipelines.MyspiderPipeline': 300,
    }複製程式碼

同時編寫 pipeline.py 檔案

import os
import csv
​
class MyspiderPipeline(object):
​
    def __init__(self):
        # csv 檔案
        store_file = os.path.dirname(__file__)+"/spiders/school1.csv"
        self.file = open(store_file,"a+",newline='',encoding="utf-8")
        self.writer = csv.writer(self.file)
​
    def process_item(self, item, spider):
        try:
     
            self.writer.writerow((
                item["uni_name"],
                item["uni_id"],
                item["city_code"],
                item["uni_type"],
                item["slogo"],
                item["rank"],
                item["safehard"]
            ))
​
        except Exception as e:
            print(e.args)
​
​
    def close_spider(self,spider):
        self.file.close()複製程式碼

好了,程式碼全部編寫完畢,還是比較簡單的吧,把上面的數字在修改成7,為啥是7,因為只能獲取到前面150條資料 


相關文章