Scrapy学習(四)マイクロブログデータの取得


前言
Scrapy学習(三)豆弁図書情報を這い出す
前編に続く.今回はログインしなければアクセスできない微博を登りに来ました.爬虫類のターゲットは、ユーザーの微博数、注目数、ファン数を取得することです.ユーザー関係図の作成(実装されていない)のためのデータ準備
の準備を
  • サードパーティ製ライブラリrequestspymongo
  • を取り付ける.
  • インストールMongoDB
  • weibo爬虫類プロジェクト
  • を作成
    Scrapyプロジェクトを作成する方法については、前の記事で説明したように、直接トピックに入ります.
    Itemsの作成
    Itemデータこの部分は個人情報、微博数、注目数、点数数などの基本情報だけでいいです.
    
    class ProfileItem(Item):
        """
              、   、      
        """
        _id = Field()
        nick_name = Field()
        profile_pic = Field()
        tweet_stats = Field()
        following_stats = Field()
        follower_stats = Field()
        sex = Field()
        location = Field()
        birthday = Field()
        bio = Field()
        
    class FollowingItem(Item):
        """
               
        """
        _id = Field()
        relationship = Field()
    
    class FollowedItem(Item):
        """
               
        """
        _id = Field()
        relationship = Field()

    Spiderの作成
    爬虫類を便利にするために、私たちが登録した入り口は携帯電話版の微博http://weibo.cn/です.ここで、マイクロブログのuidは、ユーザ資料ページにアクセスすることによって、または注目されるhref属性から取得することができる.
    class WeiboSpiderSpider(scrapy.Spider):
        name = "weibo_spider"
        allowed_domains = ["weibo.cn"]
        url = "http://weibo.cn/"
        start_urls = ['2634877355',...] #       ID
        task_set = set(start_urls) #      
        tasked_set = set() #      
        ...   
        
        def start_requests(self):
            while len(self.task_set) > 0 :
                _id = self.task_set.pop()
                if _id in self.tasked_set:
                    raise CloseSpider(reason="       %s "% (_id) )
                self.tasked_set.add(_id)
                info_url = self.url + _id
                info_item = ProfileItem()
                following_url = info_url + "/follow"
                following_item = FollowingItem()
                following_item["_id"] = _id
                following_item["relationship"] = []
                follower_url = info_url + "/fans"
                follower_item = FollowedItem()
                follower_item["_id"] = _id
                follower_item["relationship"] = []
                yield scrapy.Request(info_url, meta={"item":info_item}, callback=self.account_parse)
                yield scrapy.Request(following_url, meta={"item":following_item}, callback=self.relationship_parse)
                yield scrapy.Request(follower_url, meta={"item":follower_item}, callback=self.relationship_parse)
    
        def account_parse(self, response):
            item = response.meta["item"]
            sel = scrapy.Selector(response)
            profile_url = sel.xpath("//div[@class='ut']/a/@href").extract()[1]
            counts = sel.xpath("//div[@class='u']/div[@class='tip2']").extract_first()
            item['_id'] = re.findall(u'^/(\d+)/info',profile_url)[0]
            item['tweet_stats'] = re.findall(u'  \[(\d+)\]', counts)[0]
            item['following_stats'] = re.findall(u'  \[(\d+)\]', counts)[0]
            item['follower_stats'] = re.findall(u'  \[(\d+)\]', counts)[0]
            if int(item['tweet_stats']) < 4500 and int(item['following_stats']) > 1000 and int(item['follower_stats']) < 500:
                raise CloseSpider("   ")
            yield scrapy.Request("http://weibo.cn"+profile_url, meta={"item": item},callback=self.profile_parse)
    
        def profile_parse(self,response):
            item = response.meta['item']
            sel = scrapy.Selector(response)
            info = sel.xpath("//div[@class='tip']/following-sibling::div[@class='c']").extract_first()
            item["profile_pic"] = sel.xpath("//div[@class='c']/img/@src").extract_first()
            item["nick_name"] = re.findall(u'  :(.*?)
    ',info)[0] item["sex"] = re.findall(u' :(.*?)
    ',info) and re.findall(u' :(.*?)
    ',info)[0] or '' item["location"] = re.findall(u' :(.*?)
    ',info) and re.findall(u' :(.*?)
    ',info)[0] or '' item["birthday"] = re.findall(u' :(.*?)
    ',info) and re.findall(u' :(.*?)
    ',info)[0] or '' item["bio"] = re.findall(u' :(.*?)
    ',info) and re.findall(u' :(.*?)
    ',info)[0] or '' yield item def relationship_parse(self, response): item = response.meta["item"] sel = scrapy.Selector(response) uids = sel.xpath("//table/tr/td[last()]/a[last()]/@href").extract() new_uids = [] for uid in uids: if "uid" in uid: new_uids.append(re.findall('uid=(\d+)&',uid)[0]) else: try: new_uids.append(re.findall('/(\d+)', uid)[0]) except: print('--------',uid) pass item["relationship"].extend(new_uids) for i in new_uids: if i not in self.tasked_set: self.task_set.add(i) next_page = sel.xpath("//*[@id='pagelist']/form/div/a[text()=' ']/@href").extract_first() if next_page: yield scrapy.Request("http://weibo.cn"+next_page, meta={"item": item},callback=self.relationship_parse) else: yield item

    コードに注意すべき点はいくつかあります.
    start_url
    ここにはマイクロブログのuidを記入し、ユーザーによってはカスタムドメイン名(上記の図)があり、アクセスしてから本物のuid start_url が記入される初期シード数は10個以上である.これは、後で私たちが登った新しい種が、登っていく列に加わることを確保するためです.10個以上の規定はScrapyドキュメントから調べたものです
    REACTOR_THREADPOOL_MAXSIZE
    Default:10スレッド数はTwistedスレッドプールのデフォルトサイズです(The maximum limit for Twisted Reactor thread pool size.)
    CloseSpider
    不要な継続的な爬虫接続に遭遇した場合(すでに爬虫したリンク、定義されたゾンビ粉リンクなど)、CloseSpiderを使用して現在の爬虫スレッドを閉じることができます.
    middlewaresの作成
    class CookiesMiddleware(object):
        """  Cookie """
    
        def process_request(self, request, spider):
            cookie = random.choice(cookies)
            request.cookies = cookie

    クッキーの取得方法の作成
    ここはもともと携帯版の微博でアナログログインしようとしたのですが、どうやってコードを検証するかは難しいです.だから私は直接ネット上で誰かが書いた登録ページ版の微博のコードSinaSpiderを使って、この人はよく書いて、興味がある人は見に行くことができます.もう1人は、シミュレーションログイン(検証コード付き)を書いたテストで使用できます.ただ、私のプロジェクトにどのように埋め込むかまだ考えていません.
    # encoding=utf-8
    import json
    import base64
    import requests
    
    myWeiBo = [
        {'no': '[email protected]', 'psw': 'xx'},
        {'no': '[email protected]', 'psw': 'xx'},
    ]
    
    
    def getCookies(weibo):
        """   Cookies """
        cookies = []
        loginURL = r'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)'
        for elem in weibo:
            account = elem['no']
            password = elem['psw']
            username = base64.b64encode(account.encode('utf-8')).decode('utf-8')
            postData = {
                "entry": "sso",
                "gateway": "1",
                "from": "null",
                "savestate": "30",
                "useticket": "0",
                "pagerefer": "",
                "vsnf": "1",
                "su": username,
                "service": "sso",
                "sp": password,
                "sr": "1440*900",
                "encoding": "UTF-8",
                "cdult": "3",
                "domain": "sina.com.cn",
                "prelt": "0",
                "returntype": "TEXT",
            }
            session = requests.Session()
            r = session.post(loginURL, data=postData)
            jsonStr = r.content.decode('gbk')
            info = json.loads(jsonStr)
            if info["retcode"] == "0":
                print("Get Cookie Success!( Account:%s )" % account)
                cookie = session.cookies.get_dict()
                cookies.append(cookie)
            else:
                print("Failed!( Reason:%s )" % info["reason"].encode("utf-8"))
        return cookies
    
    cookies = getCookies(myWeiBo)
    

    上陸-反爬虫類のこの部分はプロジェクト全体で最も難しい場所であるはずだ.私はまだよく分からないところがたくさんあります.後で研究している暇がある.
    pipelinesの作成
    こちらは主にどんなタイプのItemをその表に保存すればいいですか?
    class MongoDBPipeline(object):
        def __init__(self):
            connection = MongoClient(
                host=settings['MONGODB_SERVER'],
                port=settings['MONGODB_PORT']
            )
            db = connection[settings['MONGODB_DB']]
            self.info = db[settings['INFO']]
            self.following = db[settings['FOLLOWING']]
            self.followed = db[settings['FOLLOWED']]
    
        def process_item(self, item, spider):
    
            if isinstance(item, ProfileItem):
                self.info.insert(dict(item))
            elif isinstance(item, FollowingItem):
                self.following.insert(dict(item))
            elif isinstance(item, FollowedItem):
                self.followed.insert(dict(item))
            log.msg("Weibo  added to MongoDB database!",
                    level=log.DEBUG, spider=spider)
            return item

    プログラムを実行すると、MongoDBに私たちのデータが表示されます.
    まとめ
  • settingsのうちDOWNLOAD_DELAYに5を設けることで、マイクロブログBANによって
  • が落下することを防止することができる.
  • cookiesによるログイン失敗時にシミュレーションログインを試みたが,効果は望ましくなかった
  • であった.
  • はエージェントIPプールで虫登りを試みたが,試みの失敗は主に
  • があまりできなかった.
  • は将来D 3を利用する.jsは登ったデータを描き出す
  • プロジェクトアドレス:weibo_spider