基于PySpider的weibo.cn爬虫

作为科研狗,新浪微博一生黑。一开始打算花钱买他们的商业API,结果跟我说不跟科研机构合作,我也是日了狗了。后来费尽千辛万苦写了个爬虫,差点没把我小号封了手动再见.gif本来写字的阵地主要在lofter,结果lofter这坑货不支持代码高亮,让我这个码农如何自处?好了,闲话少叙已经叙了不少,把我这三天的奋斗结果稍稍记录一下。

一些学习资料

  1. Fiddler简易使用教程 抓cookies用(必看)
  2. PySpider简易教程 整个爬虫用到的框架(必看)
  3. HTTP Header入门详解 在模拟登录过程中要涉及到http头的设置,需要了解基本信息
  4. 全程模拟新浪微博登录2015 这个分析了新浪微博网页版现在还在用的登录过程,其中使用到的最新脚本ssologin.js版本号1.4.18。不过本文主要是基于wap版的爬虫,这个没必要看,如果想进一步爬取网页版的微博可以参考学习。
  5. Sina微博爬取@pyspider 这篇文章通过用户名和密码获取wap版微博的cookies后再进行后续操作,也可参考。
  6. PyQuery文档 && CSS选择器&&Python正则表达式re package文档
    Python页面爬下来以后用于操作页面元素获取需要的内容(必看)

获取cookies用于模拟登陆

参考学习资料1里面设置好fiddler,然后打开http://weibo.cn/ 没登陆的话登陆。在登录的状态下打开你要进行爬取的页面,观察fiddler里抓到的包,得到需要的cookies信息

获取cookies

对应设置好PySpider里的crawl_config,需要注意的是cookiesheaders,考虑到我的代码逻辑我把这两个都放在crawl_config里而不是具体的爬取函数里。关于头的设置也可以参考fiddler里Headers一栏,完整代码贴在最后可以参考我的设置。

爬虫逻辑

我的需求是对于指定的用户,给出用户主页(形如http://weibo.cn/kaikai0818http://weibo.cn/u/1788136742),爬取TA全部的微博及相关信息(如发布时间、转发数等)。

入口函数on_start没什么可说的,因为设置了全局的headers和cookies这边在self.crawl的时候就不需要再发送了,如果没设置成全局的,必须在这边设置并发送。

index_page函数主要用来计算一共有多少页需要爬取,页面有一个类型为hidden<input>元素记录了一共有多少页,然后一个for得到所有需要爬取的页面地址。

list_single_page用于处理每一页微博的内容,一页有十条,主要就是操作页面获取单条微博的地址(因为后续需求可能需要爬取每一条微博的转发和评论内容)。这边有个trick,和web版微博不同的是,wap版单条微博并没有一个所谓的地址,只有一个转发或者评论的地址,代码里用了转发的地址。值得注意的是我自己测试这个爬虫的时候爬了1500条微博左右的时候账号被冻结了,建议在dashboard调一下rate、burst值。不过后来登录后激活了一下账号又能用了,还没测试过多少值可以避免被冻,因为不清楚新浪冻结的机制,我的小号还要用来花痴的,不敢瞎搞了(:з」∠)

detail_page用来处理单条微博,然后就是css选择器+正则的应用了哇,没什么可说的,就是找规律,目前测试过了没啥问题,不过爬下来的1500多条也没认真检查过,大家自己再看看了哇。

一个能跑的代码如下:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Created on 2016-03-07 13:26:00
# Project: user_timeline

import re
import time
from pyquery import PyQuery
from pyspider.libs.base_handler import *

class Handler(BaseHandler):
    user_url = "http://weibo.cn/kaikai0818"
    
    crawl_config = {
        'itag': 'v1',

        'headers': {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0',
            "Host": "weibo.cn",
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
            "Accept-Language": "zh-CN,zh-TW;q=0.8,zh-HK;q=0.6,en-US;q=0.4,en;q=0.2",
            "Accept-Encoding": "gzip, deflate",
            "DNT": "1",
            "Connection": "keep-alive"
        },

        'cookies': {
            "_T_WM":"I❤kkw(¯﹃¯)",
            "SUB":"I❤kkw(¯﹃¯)",
            "gsid_CTandWM":"I❤kkw(¯﹃¯)",
            "_T_WL":"1",
            "_WEIBO_UID":"I❤kkw(¯﹃¯)" 
        }
    }
    

    @every(minutes=24 * 60)
    def on_start(self):        
        self.crawl(Handler.user_url, callback=self.index_page,method="GET")   
    

    @config(age=1 * 24 * 60 * 60)        
    def index_page(self, response):
        #计算该用户的微博共有几页
        pages = response.doc("[type=hidden]").attr["value"]            
        for i in range(1,int(pages)+1):
            self.crawl(Handler.user_url+"?page="+str(i), callback=self.list_single_page,method="GET")
            
    
    @config(priority=2) #数字越大优先级越高
    def list_single_page(self, response):
        #处理当前页的微博        
        url = "http://weibo.cn/repost/"
        for each in response.doc("div[id^=\"M_\"]").items():             
            mid = each.attr("id")
            self.crawl(url + mid[2:], cookies = response.cookies, callback=self.detail_page) 
            #self.crawl可加上参数exetime=time.time() + 1*60 (即一分钟后再crawl)
        
            
    @config(priority=1)
    def detail_page(self, response):
        res = response.doc("#M_")
        
        #判断是否为转发
        if len(res.find("span.cmt")) != 0:
            is_rt = 1
        else:
            is_rt = 0
            
        #判断是否含图片
        if len(res.children("div").eq(1).find("img")) != 0:
            has_pic = 1
        else:
            has_pic = 0
        
        if is_rt == 0:
            text = res.find("span.ctt").text()
            orig_user = "NA"
            orig_text = "NA"
        else:
            orig_user = res("div:first-child span.cmt a").text()
            orig_text = res.find("span.ctt").text()            
            td = re.findall(r'</span>([\s\S]+)<span class=',res("div:last-child").html())            
            text = PyQuery(td[0]).text()
        return {
            "screen_name":res("div:first-child > a:first-child").text(),
            "time":res.find("span.ct").text(),
            "text":text,
            "is_rt":is_rt,
            "has_pic":has_pic,
            "orig_user":orig_user[1:],
            "orig_text":orig_text,
            "repo_cnt":re.search('\d+',response.doc("span.pms").text()).group(),
            "cmt_cnt":re.search('\d+',response.doc("span.pms").siblings().eq(0).text()).group(),
            "atti_cnt":re.search('\d+',response.doc("span.pms").siblings().eq(1).text()).group()
        } 

这辈子干得最痴汉的事情就是写了个爬虫把人一千多条微博扒拉下来了,感觉以后再也不会这么用力爱一个人了→_→
……
……
……
好了,我编不下去了,这就是科研狗的日常。doge.jpg doge.jpg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 1 前言 作为一名合格的数据分析师,其完整的技术知识体系必须贯穿数据获取、数据存储、数据提取、数据分析、数据挖掘、...
    whenif阅读 18,039评论 45 523
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 爬虫文章 in 简书程序员专题: like:128-Python 爬取落网音乐 like:127-【图文详解】py...
    喜欢吃栗子阅读 21,722评论 4 412
  • 你爬了吗? 要玩大数据,没有数据怎么玩?这里推荐一些33款开源爬虫软件给大家。 爬虫,即网络爬虫,是一种自动获取网...
    Albert新荣阅读 2,211评论 0 8
  • 离开你以后,才知道你在的意义,我想你,我梦你,我念你~但我绝不说出口!
    小尼姑1阅读 97评论 0 0