初識爬蟲 - scrapy 爬取 51 (一)

剛學會了建 scrapy 框架,當然就忍不住想去練練手了,就挑個 51 job 去了解一下職位需求情況。

前面我們已經說了如何去創建一個 scrapy 框架,以及改一下 setting 配置文件,這裏我們還要先再改一下 setting 文件:

改這裏是因爲現在很多網站都設置了反爬蟲的保護機制,如果我們不加自己設的 user-agent ,就很容易被 “ban” ,從而爬取不到我們所要的數據,當然這只是防反爬蟲的一種機制,大多數情況下都是可以的。下面是加的兩行代碼:

'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,  # 這一行是取消框架自帶的useragent
'positionspiders.rotateuseragent.RotateUserAgentMiddleware': 400    #使用自己新置的 useragent 代理 ,第一個表示我們的工程名稱,第二個是我們要新建的配置 user-agent 池的文件

那麼下面先說下配置 useragent 池的文件 rotateuseragent (文件名字自己起):

import random
# 導入useragent用戶代理模塊中的UserAgentMiddleware類
from scrapy.downloadermiddlewares.useragent import UserAgentMiddleware

# RotateUserAgentMiddleware類,繼承 UserAgentMiddleware 父類
# 作用:創建動態代理列表,隨機選取列表中的用戶代理頭部信息,僞裝請求。
#       綁定爬蟲程序的每一次請求,一併發送到訪問網址。

# 發爬蟲技術:由於很多網站設置反爬蟲技術,禁止爬蟲程序直接訪問網頁,
#             因此需要創建動態代理,將爬蟲程序模擬僞裝成瀏覽器進行網頁訪問。
class RotateUserAgentMiddleware(UserAgentMiddleware):
    # the default user_agent_list composes chrome,I E,firefox,Mozilla,opera,netscape
    # for more user agent strings,you can find it in http://www.useragentstring.com/pages/useragentstring.php
    # 編寫頭部請求代理列表
    user_agent_list = [ \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1" \
        "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", \
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", \
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", \
        "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", \
        "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", \
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", \
        "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    ]

    def __init__(self, user_agent=''):
        self.user_agent = user_agent

    def process_request(self, request, spider):
        #這句話用於隨機輪換user-agent
        ua = random.choice(self.user_agent_list)
        if ua:
            # 輸出自動輪換的user-agent
            print("本次訪問僞造的請求頭是:", ua)
            request.headers.setdefault('User-Agent', ua)
            pass
        pass

    pass

現在我們設置了動態代理,接着就可以去寫我們的爬蟲代碼了。先獲取我們的目標網址,這裏爬的是 python 的一些職位信息:

start_urls = ['https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=']

接下來我們要去目標網頁中找到目標路徑,因爲我們需要用到 xpath 路徑表達式去獲取我們需要的節點,所以我們先要去查看目標網頁源碼,找到目標節點:

即 class='el' 的div 節點下,下面就用到我們的 xpath 路徑表達式去獲取目標,如果對 xpath 不熟悉的,可以看下另一篇博客 xpath 全解

jobDivItems=response.xpath("//div[@class='el']")

我們這裏獲取的所有 div 下 class 屬性值等於 el 的標籤節點,是一個複數列表,下面我們需要對其中的一條標籤,詳細獲取其內容,這裏我們要用到 scrapy 框架下的 items 文件 ,該文件的用途見 Items 理解 。

接下來我們還需要繼續去網頁中定位我們的目標節點:

下面獲取該節點,並將獲取的目標字段,通過 Item 類進行實例化:

        jobDivItems=response.xpath("//div[@class='el']")    #這裏獲取的是當前頁下所有的職位信息
        for jobDivItem in jobDivItems:
            pItem=PositionspidersItem()         # 創建 Item 類的一個對象
            pItem['joblanguage']=PositionspiderSpider.jobType       #將字段通過 Item 對象實例化
            #print(jobDivItem.extract())

            #print(jobDivItem.extract("//p[@class='t1']/span/a/text()"))

            jobTitle = jobDivItem.xpath("//p[@class='t1 ']/span/a/text()").extract()
            # extract(): 這個方法返回的是一個數組list,裏面包含了多個string,如果只有一個string,則返回['ABC']這樣的形式。

            if len(jobTitle)>0:
                pItem['jobTitle']=jobTitle[0].strip()
                pass
            else:
                continue

            jobComp=jobDivItem.xpath("span[@class='t2']/a/text()").extract()
            jobAddress=jobDivItem.xpath("span[@class='t3']/text()").extract()
            jobSalary=jobDivItem.xpath("span[@class='t4']/text()").extract()
            jobTime=jobDivItem.xpath("span[@class='t5']/text()").extract()

            if len(jobComp)>0:
                pItem['jobComp'] = jobComp[0].strip()
                pass
            else:
                continue
            if len(jobAddress)>0:
                pItem['jobAddress'] = jobAddress[0].strip()
                pass
            else:
                continue
            if len(jobSalary)>0:
                pItem['jobSalary'] = jobSalary[0].strip()
                pass
            else:
                continue
            if len(jobTime)>0:
                pItem['jobTime'] = jobTime[0].strip()
            else:
                continue

            print(jobTitle)
            print(jobComp)
            print(jobAddress)
            print(jobSalary)
            print(jobTime)
            yield pItem
            pass

至於這個輸出,我們在管道文件中也有定義:

到這裏,我們如果輸出的話就沒問題了,但這只是一頁的數據,才幾十個,有點太少了,那下面我們就去爬下一頁的,注意這裏,是爬取下一頁的,而不是指定前幾頁,意思就是如果我們不停止程序,它會一直往後爬,直到最後一頁(現在都1337頁了,爬完不知道得多長時間,我是沒試過)。那下面就是去找下一頁的跳轉,我們看到當前頁面最下面,是關於頁數的跳轉:

我們考慮一下這裏會不會就有我們想到的信息,審查一下元素:

審查後發現,這裏的下一頁中含有一個鏈接,而這個鏈接就是下一頁的地址。到這裏就好辦了,我們只需要獲取對應路徑結點下的內容信息就行了,下面我們仍使用 xpath 來定位結點,並獲取下頁的內容:

        #開始解析下一頁代碼 獲得下一頁的超鏈接地址
        nextPageURL=response.xpath("//div[@class='p_in']/ul/li[@class='bk']/a/@href").extract()
        print("*****************",nextPageURL)
        if nextPageURL:  #如果判斷一個列表爲TUre 它是以這個列表的長度作爲判斷條件
            url=response.urljoin(nextPageURL[-1])
            print('url',url)

            yield scrapy.Request(url,self.parse,dont_filter=False)      #這一行我也比較迷
            pass
        else:
            print("退出")
        return
        pass

這裏面關鍵的那行代碼我就有點迷,當時也沒記住,爬蟲還沒深入學,也不清楚具體的使用,如果想了解的讀者,可以自行去找一下,我因爲時間問題,沒空再深入學了。

到這裏,簡單 scrapy 爬取 51 就完成了, 後面是將爬取的內容保存入庫,方面我們去看職位信息,見下一篇博客:scrapy 爬取51(二),順便把這個小項目打包放網盤裏分享一下。

 

 

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