国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Scrapy 爬取七麥 app數(shù)據(jù)排行榜

kk_miles / 1423人閱讀

摘要:目錄前言創(chuàng)建項(xiàng)目創(chuàng)建創(chuàng)建解析付費(fèi)榜運(yùn)行爬取初始列表調(diào)用腳本獲取詳情前言熟悉之后,本篇文章帶大家爬取七麥數(shù)據(jù)的付費(fèi)應(yīng)用排行榜前名應(yīng)用。根據(jù)傳入的正則表達(dá)式對(duì)數(shù)據(jù)進(jìn)行提取,返回字符串列表。

目錄

前言

創(chuàng)建項(xiàng)目

創(chuàng)建Item

創(chuàng)建Spider

解析付費(fèi)榜

運(yùn)行爬取初始app列表

Selenium調(diào)用JS腳本

獲取app詳情

前言

熟悉Scrapy之后,本篇文章帶大家爬取七麥數(shù)據(jù)(https://www.qimai.cn/rank )的ios appstore付費(fèi)應(yīng)用排行榜前100名應(yīng)用。

爬取內(nèi)容包括app在列表中的下標(biāo),app圖標(biāo)地址,app的名稱信息,app的類型,在分類中的排行,開發(fā)者,詳情等。

考慮的問題:

Forbidden by robots.txt的錯(cuò)誤

網(wǎng)頁(yè)返回403

頁(yè)面通過動(dòng)態(tài)渲染,普通的請(qǐng)求url,在頁(yè)面渲染之前已經(jīng)返回response,解析沒有數(shù)據(jù)

列表一頁(yè)20個(gè)app,想要拿到前100個(gè)需要翻頁(yè),但是翻頁(yè)沒有更改url,而是通過js動(dòng)態(tài)加載

...

創(chuàng)建項(xiàng)目

在需要放置項(xiàng)目的目錄下,

> scrapy startproject qimairank

回車即可創(chuàng)建默認(rèn)的Scrapy項(xiàng)目架構(gòu)。

創(chuàng)建Item

創(chuàng)建Item來(lái)存儲(chǔ)我們爬取的app在列表中的下標(biāo),app圖標(biāo)地址,app的名稱信息,app的類型,在分類中的排行,開發(fā)者,詳情。
修改items.py,在下面增加

class RankItem(scrapy.Item):
    # 下標(biāo)
    index = scrapy.Field()
    # 圖標(biāo)地址
    src = scrapy.Field()
    # app標(biāo)題信息
    title = scrapy.Field()
    # app類型
    type = scrapy.Field()
    # 分類中的排行
    type_rank = scrapy.Field()
    # 開發(fā)者
    company = scrapy.Field()
    # 詳情信息
    info = scrapy.Field()
創(chuàng)建Spider

spiders目錄下創(chuàng)建RankSpider.py,并創(chuàng)建class RankSpider,繼承于scrapy.Spider。

import scrapy

class RankSpider(scrapy.Spider):
    name = "RankSpider"
    start_urls = ["https://www.qimai.cn/rank"]

    def parse(self, response):
       pass

name:用于區(qū)別Spider,該名字必須是唯一的。

start_urls:Spider在啟動(dòng)時(shí)進(jìn)行爬取的url列表,首先會(huì)爬取第一個(gè)。

def parse(self, response):得到url的response信息后的解析方法。

解析付費(fèi)榜

解析用的Selectors選擇器有多種方法:

xpath(): 傳入xpath表達(dá)式,返回該表達(dá)式所對(duì)應(yīng)的所有節(jié)點(diǎn)的selector list列表 。

css(): 傳入CSS表達(dá)式,返回該表達(dá)式所對(duì)應(yīng)的所有節(jié)點(diǎn)的selector list列表.

extract(): 序列化該節(jié)點(diǎn)為unicode字符串并返回list。

re(): 根據(jù)傳入的正則表達(dá)式對(duì)數(shù)據(jù)進(jìn)行提取,返回unicode字符串list列表。

下面我們用xpath()選擇節(jié)點(diǎn),xpath的語(yǔ)法可參考w3c的http://www.w3school.com.cn/xp... 學(xué)習(xí),需要熟悉語(yǔ)法、運(yùn)算符、函數(shù)等。

def parse(self, response):
    base = response.xpath(
        "http://div[@class="ivu-row rank-all-item"]/div[@class="ivu-col ivu-col-span-8"][2]//ul/li[@class="child-item"]/div[@class="ivu-row"]")
    for box in base:
        # 創(chuàng)建實(shí)例
        rankItem = RankItem()
        # 下標(biāo)
        rankItem["index"] = 
            box.xpath(".//div[@class="ivu-col ivu-col-span-3 left-item"]/span/text()").extract()[0]
        # 圖標(biāo)地址
        rankItem["src"] = box.xpath(".//img/@src").extract()[0]
        # app名稱信息
        rankItem["title"] = box.xpath(".//div[@class="info-content"]//a/text()").extract()[0]
        # app類型
        rankItem["type"] = box.xpath(".//div[@class="info-content"]//p[@class="small-txt"]/text()").extract()[0]
        # 分類中的排行
        rankItem["type_rank"] = box.xpath(
            ".//div[@class="info-content"]//p[@class="small-txt"]//span[@class="rank-item"]/text()").extract()[
            0]
        # 開發(fā)者
        rankItem["company"] = box.xpath(
            ".//div[@class="info-content"]//p[@class="small-txt"]//span[@class="company-item"]/text()").extract()[
            0]
        # 詳情頁(yè)地址
        infoUrl = "https://www.qimai.cn" + box.xpath(".//div[@class="info-content"]//a/@href").extract()[0]
        yield rankItem
運(yùn)行爬取初始app列表

直接運(yùn)行

qimairank>scrapy crawl RankSpider -o data.json

你會(huì)發(fā)現(xiàn)窗口沒有item輸出,data.json中也沒有數(shù)據(jù),是我們寫錯(cuò)了嗎?

scrapy默認(rèn)遵守robot協(xié)議的,在訪問網(wǎng)址前會(huì)先訪問robot.txt來(lái)查看自己是否有權(quán)限訪問。如果網(wǎng)站不允許被爬,就不能訪問。
怎么樣不遵守協(xié)議呢?

settings.py

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

再次運(yùn)行仍然失敗,我們來(lái)看下具體原因:

因?yàn)槠啕溇W(wǎng)站對(duì)請(qǐng)求的User-Agent做了校驗(yàn),解決辦法是在配置文件

settings.py

# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
    #    "qimairank.middlewares.QimairankDownloaderMiddleware": 543,
    "qimairank.middlewares.RandomUserAgent": 1,
}

USER_AGENTS = [
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
    "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
    "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
    "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
    "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
    "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
    "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
    "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
]

并在middlewares.py中創(chuàng)建RandomUserAgent

import random

class RandomUserAgent(object):
    """
    隨機(jī)獲取settings.py中配置的USER_AGENTS設(shè)置"User-Agent"
    """

    def __init__(self, agents):
        self.agents = agents

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler.settings.getlist("USER_AGENTS"))

    def process_request(self, request, spider):
        request.headers.setdefault("User-Agent", random.choice(self.agents))

再次運(yùn)行,沒有報(bào)錯(cuò),但是沒有數(shù)據(jù),是我們的xpath寫錯(cuò)啦?我們?cè)趐arse中增加輸出body的信息

可以看到body為空,沒有我們需要的列表數(shù)據(jù),這是因?yàn)槠啕湐?shù)據(jù)是通過js動(dòng)態(tài)渲染的,在渲染完成前,我們的response已經(jīng)返回,那么怎么樣才能等一等呀,等到渲染完成才返回呢?

爬取動(dòng)態(tài)渲染的方式,我知道是通過Splash或者Selenium,像我們的桌面版系統(tǒng)可以選擇用Selenium,操作可以設(shè)置可視化,所有界面操作都能看見,Splash依賴于Docker,無(wú)界面。

安裝Selenium包:

pip install selenium

使用前需要安裝驅(qū)動(dòng),配置詳情點(diǎn)擊

驅(qū)動(dòng)安裝完成,在middlewares.py中創(chuàng)建 SeleniumMiddleware

class SeleniumMiddleware(object):
    def __init__(self):
        self.timeout = 50
        # 2.Firefox---------------------------------
        # 實(shí)例化參數(shù)對(duì)象
        options = webdriver.FirefoxOptions()
        # 無(wú)界面
        # options.add_argument("--headless")
        # 關(guān)閉瀏覽器彈窗
        options.set_preference("dom.webnotifications.enabled", False)
        options.set_preference("dom.push.enabled", False)
        # 打開瀏覽器
        self.browser = webdriver.Firefox(firefox_options=options)
        # 指定瀏覽器窗口大小
        self.browser.set_window_size(1400, 700)
        # 設(shè)置頁(yè)面加載超時(shí)時(shí)間
        self.browser.set_page_load_timeout(self.timeout)
        self.wait = WebDriverWait(self.browser, self.timeout)

    def process_request(self, request, spider):
        # 當(dāng)請(qǐng)求的頁(yè)面不是當(dāng)前頁(yè)面時(shí)
        if self.browser.current_url != request.url:
            # 獲取頁(yè)面
            self.browser.get(request.url)
            time.sleep(5)
        else:
            pass
        # 返回頁(yè)面的response
        return HtmlResponse(url=self.browser.current_url, body=self.browser.page_source,
                            encoding="utf-8", request=request)

    def spider_closed(self):
        # 爬蟲結(jié)束 關(guān)閉窗口
        self.browser.close()
        pass

    @classmethod
    def from_crawler(cls, crawler):
        # 設(shè)置爬蟲結(jié)束的回調(diào)監(jiān)聽
        s = cls()
        crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)
        return s

在settins.py中配置

# Enable or disable downloader middlewares
DOWNLOADER_MIDDLEWARES = {
    #    "qimairank.middlewares.QimairankDownloaderMiddleware": 543,
    "qimairank.middlewares.RandomUserAgent": 1,
    "qimairank.middlewares.SeleniumMiddleware": 10,
}

再次運(yùn)行scrapy crawl RankSpider -o data.json,啦啦啦~這回有數(shù)據(jù)啦。

Selenium調(diào)用JS腳本

觀察爬取出來(lái)的data.json,發(fā)現(xiàn)怎么肥四,只有20條數(shù)據(jù),而且除了前6個(gè)的app圖標(biāo)都是七麥的默認(rèn)圖標(biāo)。

這是因?yàn)槠啕湐?shù)據(jù)的列表默認(rèn)每頁(yè)20條,而且默認(rèn)渲染前6個(gè)的圖標(biāo),其余的頁(yè)需要觸發(fā)滑動(dòng)事件加載,而且滑動(dòng)到的圖標(biāo)才開始渲染。這樣怎么辦呢?我們只需要滑動(dòng)到可以加載的按鈕就可以啦,檢查發(fā)現(xiàn)在三個(gè)列表的外層標(biāo)簽有一個(gè)class為cm-explain-bottom的標(biāo)簽

我們用Selenium調(diào)用js腳本,滑動(dòng)到這個(gè)標(biāo)簽就可以啦,在中間件process_request方法更改

def process_request(self, request, spider):
    # 當(dāng)請(qǐng)求的頁(yè)面不是當(dāng)前頁(yè)面時(shí)
    if self.browser.current_url != request.url:
        # 獲取頁(yè)面
        self.browser.get(request.url)
        time.sleep(5)
        # 請(qǐng)求的url開始為https://www.qimai.cn/rank/時(shí),調(diào)用滑動(dòng)界面,每頁(yè)20個(gè),滑動(dòng)4次
        if request.url.startswith("https://www.qimai.cn/rank"):
            try:
                for i in (0, 1, 2, 3):
                    self.browser.execute_script(
                        "document.getElementsByClassName("cm-explain-bottom")[0].scrollIntoView(true)")
                    time.sleep(4)
            except JavascriptException as e:
                pass
            except Exception as e:
                pass

再次執(zhí)行scrapy crawl RankSpider -o data1.json,則可看見已經(jīng)生成data1.json里面有100個(gè)item。

獲取app詳情

詳情頁(yè)需要跟進(jìn)url,我們?cè)赗ankSpider#parse方法中,不用yield Item,而是yield Request就可以跟進(jìn)。

# 詳情頁(yè)地址
infoUrl = "https://www.qimai.cn" + box.xpath(".//div[@class="info-content"]//a/@href").extract()[0]
# yield rankItem
yield Request(infoUrl.replace("rank", "baseinfo"), self.parseInfo,
              meta={"rankItem": dict(rankItem).copy()}, dont_filter=True)

解析的infoUrl替換"rank"字符串為"baseinfo"就可以訪問app應(yīng)用信息頁(yè),用meta傳遞item到下一個(gè)解析方法中,用軟拷貝的方式,避免Item因?yàn)榈刂废嗤瑑?nèi)容覆蓋。

self.parseInfo為指定這次請(qǐng)求的解析方法,

def parseInfo(self, response):
    print("基地址:" + response.url)
    if response.status != 200:
        return

    rankItem = response.meta["rankItem"]

    info = dict()
    base = response.xpath("http://div[@id="app-container"]")
    if base.extract():
        # try:
        # 描述
        try:
            info["desc"] = base.xpath(
                ".//div[@class="app-header"]//div[@class="app-subtitle"]/text()").extract()[0]
        except Exception as e:
            print("無(wú)描述")
        # 開發(fā)商
        info["auther"] = base.xpath(
            ".//div[@class="app-header"]//div[@class="auther"]//div[@class="value"]/text()").extract()[0]
        # 分類
        info["classify"] = base.xpath(
            ".//div[@class="app-header"]//div[@class="genre"]//div[@class="value"]/a/text()").extract()[0]
        # appid
        info["appid"] = base.xpath(
            ".//div[@class="app-header"]//div[@class="appid"]//div[@class="value"]/a/text()").extract()[0]
        # appstore地址
        info["appstorelink"] = base.xpath(
            ".//div[@class="app-header"]//div[@class="appid"]//div[@class="value"]/a/@href").extract()[0]
        # 價(jià)格
        info["price"] = base.xpath(
            ".//div[@class="app-header"]//div[@class="price"]//div[@class="value"]/text()").extract()[0]
        # 最新版本
        info["version"] = base.xpath(
            ".//div[@class="app-header"]//div[@class="version"]//div[@class="value"]/text()").extract()[0]
        # 應(yīng)用截圖
        info["screenshot"] = base.xpath(
            ".//div[@class="router-wrapper"]//div[@class="app-screenshot"]//div[@class="screenshot-box"]//img/@src").extract()
        # 應(yīng)用描述
        info["desc"] = base.xpath(
            ".//div[@class="router-wrapper"]//div[@class="app-describe"]//div[@class="description"]").extract()[
            0]
        # 應(yīng)用基本信息
        info["baseinfo"] = []
        for infoBase in base.xpath(
                ".//div[@class="router-wrapper"]//div[@class="app-baseinfo"]//ul[@class="baseinfo-list"]/li"):
            # print(info["baseinfo"])
            try:
                info["baseinfo"].append(dict(type=infoBase.xpath(".//*[@class="type"]/text()").extract()[0],
                                             info=infoBase.xpath(".//*[@class="info-txt"]/text()").extract()[0]))
            except Exception as e:
                pass

        rankItem["info"] = info
        # 替換圖標(biāo) 列表加載為默認(rèn)圖標(biāo)
        rankItem["src"] = 
            response.xpath("http://*[@id="app-side-bar"]//div[@class="logo-wrap"]/img/@src").extract()[
                0]
        yield rankItem

再次執(zhí)行scrapy crawl RankSpider -o data1.json,則可看見已經(jīng)生成data2.json,但是生成的列表不是排行的列表,甚至是亂序的,原因是因?yàn)槲覀兪褂昧藆rl跟進(jìn)返回,每個(gè)頁(yè)面的請(qǐng)求返回的速度不一樣,需要排序的話就寫個(gè)小腳本按照index排個(gè)序。

項(xiàng)目源碼

原文鏈接

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/45201.html

相關(guān)文章

  • 零基礎(chǔ)如何學(xué)爬蟲技術(shù)

    摘要:楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲技術(shù)以供學(xué)習(xí),。本文來(lái)源知乎作者路人甲鏈接楚江數(shù)據(jù)提供網(wǎng)站數(shù)據(jù)采集和爬蟲軟件定制開發(fā)服務(wù),服務(wù)范圍涵蓋社交網(wǎng)絡(luò)電子商務(wù)分類信息學(xué)術(shù)研究等。 楚江數(shù)據(jù)是專業(yè)的互聯(lián)網(wǎng)數(shù)據(jù)技術(shù)服務(wù),現(xiàn)整理出零基礎(chǔ)如何學(xué)爬蟲技術(shù)以供學(xué)習(xí),http://www.chujiangdata.com。 第一:Python爬蟲學(xué)習(xí)系列教程(來(lái)源于某博主:htt...

    KunMinX 評(píng)論0 收藏0
  • 首次公開,整理12年積累的博客收藏夾,零距離展示《收藏夾吃灰》系列博客

    摘要:時(shí)間永遠(yuǎn)都過得那么快,一晃從年注冊(cè),到現(xiàn)在已經(jīng)過去了年那些被我藏在收藏夾吃灰的文章,已經(jīng)太多了,是時(shí)候把他們整理一下了。那是因?yàn)槭詹貖A太亂,橡皮擦給設(shè)置私密了,不收拾不好看呀。 ...

    Harriet666 評(píng)論0 收藏0
  • Python入門網(wǎng)絡(luò)爬蟲之精華版

    摘要:學(xué)習(xí)網(wǎng)絡(luò)爬蟲主要分個(gè)大的版塊抓取,分析,存儲(chǔ)另外,比較常用的爬蟲框架,這里最后也詳細(xì)介紹一下。網(wǎng)絡(luò)爬蟲要做的,簡(jiǎn)單來(lái)說(shuō),就是實(shí)現(xiàn)瀏覽器的功能。 Python學(xué)習(xí)網(wǎng)絡(luò)爬蟲主要分3個(gè)大的版塊:抓取,分析,存儲(chǔ) 另外,比較常用的爬蟲框架Scrapy,這里最后也詳細(xì)介紹一下。 首先列舉一下本人總結(jié)的相關(guān)文章,這些覆蓋了入門網(wǎng)絡(luò)爬蟲需要的基本概念和技巧:寧哥的小站-網(wǎng)絡(luò)爬蟲,當(dāng)我們?cè)跒g覽器中輸入...

    Bmob 評(píng)論0 收藏0
  • Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---10、爬蟲框架的安裝:PySpider、Scrapy

    摘要:所以如果對(duì)爬蟲有一定基礎(chǔ),上手框架是一種好的選擇。缺少包,使用安裝即可缺少包,使用安裝即可上一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)爬取相關(guān)庫(kù)的安裝的安裝下一篇文章網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)爬蟲框架的安裝 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---9、APP爬取相關(guān)庫(kù)的安裝:Appium的安裝下一篇文章:Python3網(wǎng)絡(luò)爬蟲實(shí)戰(zhàn)---11、爬蟲框架的安裝:ScrapySplash、ScrapyRedis 我們直接...

    張憲坤 評(píng)論0 收藏0
  • scrapy入門

    摘要:快速入門首先,初步要做的就是快速構(gòu)建一個(gè)爬蟲。然后把結(jié)果加入到一個(gè)隊(duì)列中。既然是入門,我們肯定是先關(guān)心我們需要的。 因?yàn)楣卷?xiàng)目需求,需要做一個(gè)爬蟲。所以我一個(gè)python小白就被拉去做了爬蟲。花了兩周時(shí)間,拼拼湊湊總算趕出來(lái)了。所以寫個(gè)blog做個(gè)記錄。 快速入門 首先,初步要做的就是快速構(gòu)建一個(gè)爬蟲。 配置環(huán)境 Mac下安裝 1) 直接從官網(wǎng)下載 python下載官網(wǎng) 2) 是通過...

    CrazyCodes 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<