1. 程式人生 > >【Python實戰】Scrapy豌豆莢應用市場爬蟲

【Python實戰】Scrapy豌豆莢應用市場爬蟲

對於給定的大量APP,如何爬取與之對應的(應用市場)分類、描述的資訊?且看下面分解。

1. 頁面分析

當我們在豌豆莢首頁搜尋框輸入微信後,會跳轉到搜尋結果的頁面,其url為http://www.wandoujia.com/search?key=%微信。搜尋結果一般是按相關性排序的;所以,我們認為第一條搜尋結果為所需要爬取的。緊接著,點進去後會跳轉到頁面http://www.wandoujia.com/apps/com.tencent.mm,我們會發現豌豆莢的APP的詳情頁,是www.wandoujia.com/apps/ + APP package組成。

讓我們退回到搜尋結果頁面,分析頁面元素,如圖:

所有搜尋結果在<ul>

無序列表標籤中,每一個搜尋結果在<li>標籤中。對應地,CSS選擇器應為

'#j-search-list>li::attr(data-pn)'

接下來,我們來分析APP的詳情頁,APP的名稱所對應的HTML元素如圖:

APP類別的如圖:

APP描述的如圖:

不難得到這三類元素所對應的CSS選擇器

.app-name>span::text
.crumb>.second>a>span::text
.desc-info>.con::text

通過上面的分析,確定爬取策略如下:

  • 逐行讀取APP檔案,拼接搜尋頁面URL;
  • 分析搜尋結果頁面,跳轉到第一條結果對應的詳情頁;
  • 爬取詳情頁相關結果,寫到輸出檔案

2. 爬蟲實現

分析完頁面,可以coding寫爬蟲了。但是,若裸寫Python實現,則要處理下載間隔、請求、頁面解析、爬取結果序列化。Scrapy提供一個輕量級、快速的web爬蟲框架,並很好地解決了這些問題;中文doc有比較詳盡的介紹。

資料清洗

APP檔案中,可能有一些名稱不規整,需要做清洗:

# -*- coding: utf-8 -*-
import re


def clean_app_name(app_name):
    space = u'\u00a0'
    app_name = app_name.replace(space, '')
    brackets = r'\(.*\)|\[.*\]|【.*】|(.*)'
    return re.sub(brackets, '', app_name)

URL處理

拿清洗後APP名稱,拼接搜尋結果頁面URL。因為URL不識別中文等字元,需要用urllib.quote做URL編碼:

# -*- coding: utf-8 -*-
from appMarket import clean
import urllib


def get_kw_url(kw):
    """concatenate the url for searching"""

    base_url = u"http://www.wandoujia.com/search?key=%s"
    kw = clean.clean_app_name(kw)
    return base_url % (urllib.quote(kw.encode("utf8")))


def get_pkg_url(pkg):
    """get the detail url according to pkg"""

    return 'http://www.wandoujia.com/apps/%s' % pkg

爬取

Scrapy的爬蟲均繼承與scrapy.Spider類,主要的屬性及方法:

  • name,爬蟲的名稱,scrapy crawl命令後可直接跟爬蟲的名稱,即可啟動該爬蟲
  • allowed_domains,允許爬取域名的列表
  • start_requests(),開始爬取的方法,返回一個可迭代物件(iterable),一般為scrapy.Request物件
  • parse(response),既可負責處理response並返回處理的資料,也可以跟進的URL(以做下一步處理)

items為儲存爬取後資料的容器,類似於Python的dict,

import scrapy


class AppMarketItem(scrapy.Item):
    # define the fields for your item here like:
    kw = scrapy.Field()  # key word
    name = scrapy.Field()  # app name
    tag = scrapy.Field()  # app tag
    desc = scrapy.Field()  # app description

豌豆莢Spider程式碼:

# -*- coding: utf-8 -*-
# @Time    : 2016/6/23
# @Author  : rain
import scrapy
import codecs
from appMarket import util
from appMarket.util import wandoujia
from appMarket.items import AppMarketItem


class WandoujiaSpider(scrapy.Spider):
    name = "WandoujiaSpider"
    allowed_domains = ["www.wandoujia.com"]

    def __init__(self):
        self.apps_path = './input/apps.txt'

    def start_requests(self):
        with codecs.open(self.apps_path, 'r', 'utf-8') as f:
            for app_name in f:
                yield scrapy.Request(url=wandoujia.get_kw_url(app_name),
                                     callback=self.parse_search_result,
                                     meta={'kw': app_name.rstrip()})

    def parse(self, response):
        item = AppMarketItem()
        item['kw'] = response.meta['kw']
        item['name'] = response.css('.app-name>span::text').extract_first()
        item['tag'] = response.css('.crumb>.second>a>span::text').extract_first()
        desc = response.css('.desc-info>.con::text').extract()
        item['desc'] = util.parse_desc(desc)
        item['desc'] = u"" if not item["desc"] else item["desc"].strip()
        self.log(u'crawling the app %s' % item["name"])
        yield item

    def parse_search_result(self, response):
        pkg = response.css("#j-search-list>li::attr(data-pn)").extract_first()
        yield scrapy.Request(url=wandoujia.get_pkg_url(pkg), meta=response.meta)

APP檔案裡的應用名作為搜尋詞,也應被寫在輸出檔案裡。但是,在爬取時URL有跳轉,如何在不同層級間的Request傳遞變數呢?Request中的meta (dict) 引數實現了這種傳遞。

APP描述.desc-info>.con::text,extract返回的是一個list,拼接成string如下:

def parse_desc(desc):
    return reduce(lambda a, b: a.strip()+b.strip(), desc, '')

結果處理

Scrapy推薦的序列化方式為Json。Json的好處顯而易見:

  • 跨語言;
  • Schema明晰,較於'\t'分割的純文字,讀取不易出錯

爬取結果有可能會有重複的、為空的(無搜尋結果的);此外,Python2序列化Json時,對於中文字元,其編碼為unicode。對於這些問題,可自定義Pipeline對結果進行處理:

class CheckPipeline(object):
    """check item, and drop the duplicate one"""
    def __init__(self):
        self.names_seen = set()

    def process_item(self, item, spider):
        if item['name']:
            if item['name'] in self.names_seen:
                raise DropItem("Duplicate item found: %s" % item)
            else:
                self.names_seen.add(item['name'])
                return item
        else:
            raise DropItem("Missing price in %s" % item)


class JsonWriterPipeline(object):
    def __init__(self):
        self.file = codecs.open('./output/output.json', 'wb', 'utf-8')

    def process_item(self, item, spider):
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"
        self.file.write(line)
        return item

還需在settings.py中設定

ITEM_PIPELINES = {
    'appMarket.pipelines.CheckPipeline': 300,
    'appMarket.pipelines.JsonWriterPipeline': 800,
}

分配給每個類的整型值,確定了他們執行的順序,按數字從低到高的順序,通過pipeline,通常將這些數字定義在0-1000範圍內。

相關推薦

Python實戰Scrapy豆莢應用市場爬蟲

對於給定的大量APP,如何爬取與之對應的(應用市場)分類、描述的資訊?且看下面分解。 1. 頁面分析 當我們在豌豆莢首頁搜尋框輸入微信後,會跳轉到搜尋結果的頁面,其url為http://www.wandoujia.com/search?key=%微信。搜尋結果一般是按相關性排序的;所以,我們認為第一條搜尋結果

Python實戰用Scrapyd把Scrapy爬蟲一步一步部署到騰訊雲

將我們的爬蟲部署到騰訊雲伺服器上面。廢話不多說,我們就來實戰操作吧。 這裡選擇什麼雲服務都是可以的,阿里雲,AWS,騰訊雲,其他雲都是沒有問題的。部署方法基本一樣,這裡為了方便,所以筆者選擇了騰訊雲來做講解。 既然我們選擇了騰訊雲,首先去騰訊雲的官網,註冊登入一下。 點選複製https:

Python實戰機型自動化標註(搜狗爬蟲實現)

1. 引言 從安卓手機收集上來的機型大都為這樣: mi|5 mi|4c mi 4c 2014022 kiw-al10 nem-tl00h 收集的機型大都雜亂無章,不便於做統計分析。因此,標註顯得尤為重要。 中關村線上有對國內大部分手機的介紹情況,包括手機機型nem-tl00h及其對應的常見名稱榮耀暢玩5C

Python實戰Pandas:讓你像寫SQL一樣做資料分析(二)

1. 引言 前一篇介紹了Pandas實現簡單的SQL操作,本篇中將主要介紹一些相對複雜一點的操作。為了方便後面實操,先給出一份簡化版的裝置統計資料: 0 android NLL 387546520 2099457911 0 ios NLL 52877990 916421755 1 and

Python實戰Pandas:讓你像寫SQL一樣做資料分析(一)

1. 引言 Pandas是一個開源的Python資料分析庫。Pandas把結構化資料分為了三類: Series,1維序列,可視作為沒有column名的、只有一個column的DataFrame; DataFrame,同Spark SQL中的DataFrame一樣,其概念來自於R語言,為多column並sch

Python實戰Django建站筆記

前一段時間,用Django搭建一個報表分析的網站;藉此正好整理一下筆記。 1. 安裝 python有包管理工具pip,直接cd Python27/Scripts,輸入 pip install django # install by version pip install --upgrade Django==

豆莢應用市場上傳時提示“抽取icon失敗”解決方案

轉載請註明出處 http://blog.csdn.net/u014513456/article/details/53646034 背景:APP開發完畢後,渠道包給運營同學,在上傳豌豆莢市場時報錯“您的應用抽取Icon失敗,請技術人員確認Icon

專案實戰python:MongoDB資料庫的操作及練習

python:MongoDB資料庫的操作及練習 import pymongo class MongodbConn(object): def __init__(self): self.CONN = pymongo.MongoClient("mongodb:/

專案實戰python:寫檔案個性化設定模組Python_Xlwt練習

python:寫檔案個性化設定模組Python_Xlwt練習 # -*- coding: utf-8 -*- """ Created on Sun Aug 5 22:52:22 2018 @author: A3 """ # ================

專案實戰Python :視訊網站資料清洗整理和結論研究

視訊網站資料清洗整理和結論研究 要求: 1、資料清洗 - 去除空值 要求:建立函式 提示:fillna方法填充缺失資料,注意inplace引數 2、資料清洗 - 時間標籤轉化 要求: ① 將時間欄

實戰scrapy 爬取果殼問答!

引言 學爬蟲的同學都知道,Scrapy是一個非常好用的框架,可以大大的簡化我們編寫程式碼的工作量。今天我們就從使用Scrapy爬取果殼問答。 需求分析 爬取果殼問答中精彩回答的標題和答案。 知識點 爬取資料:Scrapy 資料庫:Mongo 建立專案

JUnit實戰應用程式Controller設計單元測試

在本章中,我們為一個簡單但完整的應用程式controller建立了一個測試用例。測試用例並不是測試單個的元件,而是檢驗多個組例,如何一起工作。我們從一個可以用於任何類的簡單測試用例開始.然後把新的測試逐個新增到測試用例中,直到所有初始的元件都被測試到。由於斷言變

實戰scrapy-redis + webdriver 爬取航空網站

引言 今天給大家帶來的是scrapy-redis + webdriver實戰案例。在爬蟲編寫過程中,我們經常會遇到以下的情況,想要用scrapy框架,但是因為網站的原因,還想要用webdriver,那麼要如何實現scrapy + webdriver呢?其實很簡單,大家都知道,在scrapy中,我

支援向量機SVM演算法應用Python實現

from __future__ import print_function from time import time import logging import matplotlib.pyplot as plt from sklearn.cross_validation import train_te

TensorFlow實戰Python實現自編碼器

程式碼: import numpy as np import sklearn.preprocessing as prep import tensorflow as tf from tensorflow.examples.tutorials.mnist impor

專案實戰:基於python的p2p運營商資料資訊的特徵挖掘

######【風控建模】 基於python的p2p運營商資料資訊的特徵挖掘 **@author: sunyaowu** **@datetime: 2018年8月** 說明:利用平臺數據和第三方資料建立基於使用者通訊資訊的反欺詐規則,判別通訊資

python自制讓大白成為你的個人助手!

article get content clas tps com class out 自制 我做這個軟件就是要讓賣萌進行究竟! 官方站點:http://www.jackeriss.com/companions.htm GitHub:https://github.co

Python學習Python解決漢諾塔問題

次數 代碼 int 解題思路 move python學習 求解 color 印度 參考文章:http://www.cnblogs.com/dmego/p/5965835.html 一句話:學程序不是目的,理解就好;寫代碼也不是必然,省事最好;拿也好,查也好,解決問題就好

機器學習1 監督學習應用與梯度下降

例如 tla ges 機器 fprintf lns 找到 輸入 style 監督學習 簡單來說監督學習模型如圖所示 其中 x是輸入變量 又叫特征向量 y是輸出變量 又叫目標向量 通常的我們用(x,y)表示一個樣本 而第i個樣本 用(x(i),y(i))表示 h是輸出函

20170721L08-02-02老男孩Linux運維實戰培訓初級第八節課課前上機實戰考試講解

sersync主要還是講rsync的實踐上機實驗還有寫一些腳本下面是自動備份的腳本#bak site and logscd /var/html && tar zcf /backup/www_$(date +%F).tar.gz ./wwwcd /app && tar zc