Scrapyを使ったFossdroidのAPK-crawl

FossdroidというAndroidOSSのアプリを集めたサイトがある。ここにあるアプリの内HTMLハイブリッドアプリが欲しくて、集めようとした備忘録

Scrapyとshellscriptを使ったよ

Scrapyのインストー

$ sudo pip install --upgrade pip
$ sudo pip install pyopenssl
$ sudo pip install --upgrade pyopenssl
$ sudo pip install scrapy
$ sudo pip install --upgrade Scrapy

pipでいれればいいけど色々エラーが起きたのでその度調べて解決、最終的には私は上のコマンドを打ってインストール完了

Scrapyを使ったcrawl

プロジェクトの作成

まずはクロールを行うプロジェクトを作成する.scrapy startproject プロジェクト名で作成

$ scrapy startproject apkcrawl

設定ファイルの編集

今回対象とするfossdroid.comのrobots.txtに従うように、かつ負荷をかけないようにDELAYをつける

ROBOTSTXT_OBEYTrueになっていること(デフォルトでTrueなので問題ないはず)

DOWNLOAD_DELAYコメントアウトをはずし3と設定する

$ cd apkcrawl/apkcrawl
$ vim settings.py


# -*- coding: utf-8 -*-

# Scrapy settings for apkcrawl project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     http://doc.scrapy.org/en/latest/topics/settings.html
#     http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html
#     http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html

BOT_NAME = 'apkcrawl'

SPIDER_MODULES = ['apkcrawl.spiders']
NEWSPIDER_MODULE = 'apkcrawl.spiders'


# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'apkcrawl (+http://www.yourdomain.com)'

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 3

(snipping)

保存するデータのクラスを作成

crawlした際に保存するデータのクラスを作成する.

今回はapkのタイトルとapkのurlを保存したいので、そういったクラスとする

$ vim items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy
    

class ApkcrawlItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field() # name of application
    url = scrapy.Field() # url of APK

crawl本体を書く

scrapy genspider クロールファイル名 集めたいデータのurlでクロール本体のスクリプトファイルを作成

クロールファイル名は何でもいいので私はapkcrawl_spider,fossdroidからデータを集めるので集めたいデータのurlはfossdroid.comとなる

$ scrapy genspider apkcrawl_spider fossdroid.com
$ vim spiders/apkcrawl_spider.py

# -*- coding: utf-8 -*-
from ..items import ApkcrawlItem
import scrapy


class ApkcrawlSpiderSpider(scrapy.Spider):
    name = 'apkcrawl_spider'
    allowed_domains = ['fossdroid.com']
    start_urls = (
            'http://fossdroid.com/c/system/whats_new.html',
            'http://fossdroid.com/c/internet/whats_new.html',
            'http://fossdroid.com/c/multimedia/whats_new.html',
            'http://fossdroid.com/c/games/whats_new.html',
            'http://fossdroid.com/c/navigation/whats_new.html',
            'http://fossdroid.com/c/time/whats_new.html',
            'http://fossdroid.com/c/writing/whats_new.html',
            'http://fossdroid.com/c/science-education/whats_new.html',
            'http://fossdroid.com/c/reading/whats_new.html',
            'http://fossdroid.com/c/connectivity/whats_new.html',
            'http://fossdroid.com/c/theming/whats_new.html',
            'http://fossdroid.com/c/security/whats_new.html',
            'http://fossdroid.com/c/development/whats_new.html',
            'http://fossdroid.com/c/money/whats_new.html',
            'http://fossdroid.com/c/sports-health/whats_new.html',
            'http://fossdroid.com/c/phone-sms/whats_new.html',
            'http://fossdroid.com/c/graphics/whats_new.html'
            )


    def parse(self, response):
        for res in response.css("h5"):
            apk = ApkcrawlItem()
            apk['title'] = res.css("a::text").extract_first()
            print(apk['title'])
            nextpage = res.css("a::attr('href')").extract_first()
            print(nextpage)
            if nextpage:
                url = response.urljoin(nextpage)
                apk['url'] = url

            yield apk

start_urlsにはクロールするurlを書いておく。start_urlsに書いてあるurl毎にparse関数を実行していくことになる.

あとはfossdroidのソースコードを確認していく。urlから更にurlを入手してcrawlしていく方法がわからなかったため、ここではアプリケーションページのurlを入手することにした.

scrapyの実行

$ scrapy crawl apkcrawl_spider -o apklist.json

-oで書き出すjsonファイルを指定する.

入手したいapkのファイルは入手したアプリケーション名.htmlのhtmlをapkに変えるだけで良いとわかったのでここからはスクリプトを書く

apkのダウンロード

文字列を置換してひたすらwgetするだけ.保存用のディレクトリapkを作成しておく

import json
import os

f = open("apklist.json","r")
apklist = []
json_data = json.load(f)
for i in range(len(json_data)):
    url = json_data[i]['url'].replace("html","apk")
    os.system("wget "+url+" -P apk")

HTMLハイブリッドアプリの判別

最後に集めたapkの中からHTMLハイブリッドアプリを判別する.apkの実体はzipファイルなのでunzipしてhtmlファイルがあるかないかで判別を行う

事前に作業ディレクトリであるtmpディレクトリとhtmlハイブリッドアプリのapkファイルを保存するhtmlapkディレクトリを作成しておく

#!/bin/bash
for file in `\find ./apk -maxdepth 1 -type f`; do
    unzip -d ./tmp $file
    htmlfile=`find ./tmp/ -type f -name "*.html"`
    for a in $htmlfile; do
        cp $file ./htmlapk/
        break
    done
    rm -r ./tmp/*
done

参考