Python爬虫入门教程 16-100 500px摄影师社区抓取摄影师数据

写在前面

今天要抓取的网站为 https://500px.me/ ,这是一个摄影社区,在一个摄影社区里面原本应该爬取的是图片信息,但是我发现好像也没啥有意思的,突然以为爬取一下这个网站的摄影师更好玩一些,因此就有了这篇文章的由来。redis

基于上面的目的,我找了了一个不错的页面 https://500px.me/community/search/user mongodb

在这里插入图片描述

不过细细分析以后,发现这个页面并不能抓取到尽量多的用户,由于下拉一段时间,就不能继续了,十分糟心,难道我止步于此了么,显然不可能的,一番的努力以后(大概废了1分钟吧),我找到了突破口,任意打开一个用户的我的中心页,就是点击上述连接的任意用户头像,出现以下操做。json

在这里插入图片描述

用户我的中心页面,居然有关注列表唉~~,nice啊,这个好趴啊,F12分析一下。 网络

在这里插入图片描述

哒哒哒,数据获得了。 URL是 https://500px.me/community/res/relation/4f7fe110d4e0b8a1fae0632b2358c8898/follow?startTime=&page=1&size=10&type=jsonapp

参数分别以下,实际测试发现size能够设置为100dom

https://500px.me/community/res/relation/{用户ID}/follow?startTime=&page={页码}&size={每页数据}&type=json
复制代码

那么咱们只须要这么作就能够了测试

  1. 获取关注总数
  2. 关注总数除以100,循环获得全部的关注者(这个地方为何用关注,不用粉丝,是由于被关注的人更加有价值) 明确咱们的目标以后,就能够开始写代码了。

撸代码

基本操做,获取网络请求,以后解析页面,取得关注总数。网站

用户的起始,我选择的id是5769e51a04209a9b9b6a8c1e656ff9566,你能够随机选择一个,只要他有关注名单,就能够。 导入模块,这篇博客,用到了redismongo,因此相关的基础知识,我建议你提早准备一下,不然看起来吃力。ui

import requests
import threading

from redis import StrictRedis
import pymongo

#########mongo部分#########################
DATABASE_IP = '127.0.0.1'
DATABASE_PORT = 27017
DATABASE_NAME = 'sun'
client = pymongo.MongoClient(DATABASE_IP,DATABASE_PORT)
db = client.sun
db.authenticate("dba", "dba")
collection = db.px500  # 准备插入数据

#########mongo部分#########################

#########redis部分#########################
redis = StrictRedis(host="localhost",port=6379,db=1,decode_responses=True)
#########redis部分#########################


#########全局参数部分#########################
START_URL = "https://500px.me/community/v2/user/indexInfo?queriedUserId={}" # 入口连接
COMMENT = "https://500px.me/community/res/relation/{}/follow?startTime=&page={}&size=100&type=json"
HEADERS = {
    "Accept":"application/json",
    "User-Agent":"你本身去找找可用的就行",
    "X-Requested-With":"XMLHttpRequest"
}

need_crawlids = []  # 待爬取的userid

lock = threading.Lock() # 线程锁
#########全局参数部分#########################
复制代码
def get_followee():
    try:
        res = requests.get(START_URL.format("5769e51a04209a9b9b6a8c1e656ff9566"),
        headers=HEADERS,timeout=3)
        data = res.json()
        if data:
            totle = int(data["data"]["userFolloweeCount"])  # 返回关注数
            userid = data["data"]["id"]	# 返回用户ID
            return {
                "userid":userid,
                "totle":totle
            }  # 返回总数据
    except Exception as e:
        print("数据获取错误")
        print(e)
if __name__ == '__main__':
    start = get_followee()  # 获取入口
    need_crawlids.append(start)
    
复制代码

上面代码中有一个很是重要的逻辑,就是为何要先匹配种子地址的【关注数】和【用户ID】,这两个值是为了拼接下面的URL https://500px.me/community/res/relation/{}/follow?startTime=&page={}&size=100&type=json 通过分析,你已经知道,这个地方第一个参数是用户id,第二个参数是页码page,page须要经过关注总数除以100获得。不会算的,好好在纸上写写吧~spa

咱们能够经过一个方法,获取到了种子用户的关注列表,以此继续爬取下去,完善生产者代码。关键代码都进行了注释标注。

思路以下:

  1. 死循环不断获取need_crawlids 变量中的用户,而后获取该用户的关注者列表。
  2. 爬取到的信息,写入redis方便验证重复,快速存储。
class Product(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self._headers = HEADERS

    def get_follows(self,userid,totle):
        try:
            res = requests.get(COMMENT.format(userid,totle),headers=HEADERS,timeout=3)
            data = res.json()

            if data:
                for item in data:
                    yield {
                        "userid":item["id"],
                        "totle":item["userFolloweeCount"]
                    }
        except Exception as e:
            print("错误信息")
            print(e)
            self.get_follows(userid,totle)  # 出错以后,从新调用

    def run(self):

        while 1:
            global need_crawlids  # 调用全局等待爬取的内容

            if lock.acquire():
                if len(need_crawlids)==0:  # 若是为0,没法进入循环
                    continue

                data = need_crawlids[0]  # 取得第一个
                del need_crawlids[0]  # 使用完删除

                lock.release()

            if data["totle"] == 0:
                continue

            for page in range(1,data["totle"]//100+2):
                for i in self.get_follows(data["userid"],page):
                    if lock.acquire():
                        need_crawlids.append(i)  # 新获取到的,追加到等待爬取的列表里面
                        lock.release()
                    self.save_redis(i)  # 存储到redis里面


    def save_redis(self,data):
        redis.setnx(data["userid"],data["totle"])
        #print(data,"插入成功")

复制代码

因为500px无反爬虫,因此运行起来速度也是飞快了,一会就爬取了大量的数据,目测大概40000多人,因为咱是写教程的,我中止了爬取。

在这里插入图片描述

这些数据不能就在redis里面趴着,咱们要用它获取用户的全部信息,那么先找到用户信息接口,其实在上面已经使用了一次 https://500px.me/community/v2/user/indexInfo?queriedUserId={} 后面的queriedUserId对应的是用户id,只须要从刚才的数据里面获取redis的key就能够了,开始编写消费者代码吧,我开启了5个线程抓取。

class Consumer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while 1:
            key = redis.randomkey() # 随机获取一个key
            if key:
                # 删除获取到的key
                redis.delete(key)
                self.get_info(key)



    def get_info(self,key):
        try:
            res = requests.get(START_URL.format(key),headers=HEADERS,timeout=3)
            data = res.json()
            if data['status'] == "200":
                collection.insert(data["data"])  # 插入到mongodb中
        except Exception as e:
            print(e)
            return
if __name__ == '__main__':
    start = get_followee()  # 获取入口
    need_crawlids.append(start)


    p = Product()
    p.start()

    for i in range(1,5):
        c = Consumer()
        c.start()

复制代码

代码没有特别须要注意的,能够说很是简单了,关于redis使用也很少。

redis.randomkey() # 随机获取一个key
redis.delete(key)  # 删除key
复制代码

(⊙o⊙)…通过几分钟的等待以后,大量的用户信息就来到了个人本地。

完整代码评论留言发送。

写在后面

emmmmmm...... 每天在CSDN写博客,明天就爬CSDN博客吧~~~

相关文章
相关标签/搜索