解析粉丝信息字段及循环爬取,清洗并存入数据库

简介:desc1

其实有gender数组,然而性别默认为null(男)。查看了几个粉丝信息后,发觉不管男女这个数组的值仍然为null,所以这儿没有取用这个信息。用户的详尽信息在其主页可以查看。

####3.1items

解析粉丝信息字段及循环爬取,清洗并存入数据库

确定好信息数组后就可以编撰items.py

class SinaItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    fid = scrapy.Field()
    screen_name = scrapy.Field()
    profile_image_url = scrapy.Field()
    profile_url = scrapy.Field()
    followers_count = scrapy.Field()
    follow_count = scrapy.Field()
    desc1 = scrapy.Field()

####3.2spider/

import scrapy
import json
import jsonpath
from sina.items import SinaItem
class FansSpider(scrapy.Spider):
    name = 'fans'
    allowed_domains = ['m.weibo.cn']
    #  博主url
    url = "https://m.weibo.cn/api/container/getIndex?containerid=231051_-_fans_-_3217179555&since_id="
    offset = 1
    start_urls = [url+str(offset),]
    def parse(self, response):
        result = json.loads(response.text)
        cardgroup = jsonpath.jsonpath(result,"$..card_group")[0] # jsonpath返回一个列表
        for fan in cardgroup:
            # type(fan) --> dict
            item = SinaItem()
            item['fid'] = jsonpath.jsonpath(fan, "$..id")
            item['screen_name'] = jsonpath.jsonpath(fan, "$..screen_name")
            item['profile_image_url'] = jsonpath.jsonpath(fan, "$..profile_image_url")
            item['profile_url'] = jsonpath.jsonpath(fan, "$..profile_url")
            item['followers_count'] = jsonpath.jsonpath(fan, "$..followers_count")
            item['follow_count'] = jsonpath.jsonpath(fan, "$..follow_count")
            item['desc1'] = jsonpath.jsonpath(fan, "$..desc1")
            yield item
        self.offset += 1
        yield scrapy.Request(self.url + str(self.offset), callback=self.parse)

offset为偏斜量,解析完成以后再发送恳求就可以完成循环爬取。

####3.3pipelines.py

管线文件有两个类,一个负责清洗,一个负责存入数据库。

class Qingxi(object):
    def process_item(self, item, spider):
        item['fid'] = item['fid'][0]
        item['screen_name'] = item['screen_name'][0]
        item['profile_image_url'] = item['profile_image_url'][0]
        item['profile_url'] = item['profile_url'][0]
        item['followers_count'] = item['followers_count'][0]
        item['follow_count'] = item['follow_count'][0]
        item['desc1'] = item['desc1'][0]
        return item

因为JsonPath返回的是一个列表,所以我们须要取出第一个元素,实际上也只有一个元素,不然不好存入数据库。

class SinaPipeline(object):
    def __init__(self, host, user, password, database,port):
        self.host = host
        self.user = user
        self.password = password
        self.database = database
        self.port = port
    def process_item(self, item, spider):
        sql = "insert into HuiYiZhuanYongXiaoMaJia (fid, screen_name, profile_image_url, profile_url, followers_count, follow_count, desc1) values (%s,%s,%s,%s,%s,%s,%s);"
        self.cursor.execute(sql, [item['fid'], item['screen_name'], item['profile_image_url'], item['profile_url'], item['followers_count'], item['follow_count'], item['desc1']])
        self.conn.commit()
        return item
    @classmethod
    def from_crawler(cls,crawler):
        #从settings.py 里获取配置信息
        return cls(
            host=crawler.settings.get('MYSQL_HOST'),
            user=crawler.settings.get('MYSQL_USER'),
            password=crawler.settings.get('MYSQL_PASSWORD'),
            database=crawler.settings.get('MYSQL_DATABASE'),
            port=crawler.settings.get('MYSQL_PORT')
        )
    def open_spider(self,spider):
        """
        当Spider开启时,这个方法被调用
        :param spider: Spider 的实例
        :return:
        """
        self.conn = pymysql.connect(
            host =self.host,
            user=self.user,
            password=self.password,
            database=self.database,
            port=self.port,
            charset='utf8'
        )
        self.cursor = self.conn.cursor()
    def close_spider(self, spider):
        """
        当Spider关闭时,这个方法被调用
        :param spider:
        :return:
        """
        self.cursor.close()
        self.conn.close()

####3.4middlewares.py

在刚开始没有设置User-Agent和下载延后的时侯,恳请次数达到40多次后响应状态码变为了418:Iamateapot。特定搜索了一个418哪些意思。

“客户端错误响应代码表示服务器拒绝泡制奶茶,由于它是一个茶杯。这个错误是超文本奶茶壶控制合同的参考,这是1998年愚人节的笑话。”

新浪还搞了这一手o_o…

这儿下载中间件主要拿来设置随机的User-Agent。

import random
class SinaDownloaderMiddleware(object):
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.
    def __init__(self):
        self.user_agents = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134',
            'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',
            'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
            'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
            'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)'
        ]
    def process_request(self, request, spider):
        request.headers['User-Agent'] = random.choice(self.user_agents)
        return None

####3.5最后在setting文件里开启相关配置即可。

假如我们要抓取粉丝的详尽数据,例如性别,地址,中学,注册时间等可以再发送一个恳求给粉丝的主页链接,而主页链接我们早已领到了:profile_url,然后再写一个解析函数即可。

推论

我们发觉最后爬取的结果只有四千多条。(简介有表情符号写不进数据库)

这是由于我们直接拿恳求url在浏览器里测试:

fans-_2656274875&since_id=250,当测试到250页的时侯会有返回数据。一页20条,总共5000条。

并且当测试到251页的时侯,就没有数据了。

刚开始怀疑的是莫非这个大V博主只有5000多粉丝,而且又认为不太可能,即便粉丝数目显示的是3900多万。后来换了几个博主进行测试同样发觉了这个问题微博粉丝链接,认为是微博只会显示5000条数据。由于我们抓的是m.weibo.cn,也就是说,我们拿着手机在查看博主全部粉丝的时侯若果仍然往下降仍然往下降,最多只会显示5000条数据。(这个推论是测试了卫视新闻帐号得出的微博粉丝链接,应当不只5000人关注了卫视新闻吧)

######PS最后我又测试了一下一个只有3000多粉丝的博主,粉丝结果竟然只有5页,也就是100多个粉丝。并且首页显示的是3087,所以大约能得出这个博主其实可能是买的数据吧(由于我去买了2000粉丝,结果粉丝列表只有三个人)( ̄﹏ ̄;)

综上:本次爬取新浪微博用户粉丝数据没有哪些卵用。

代码Github地址: