社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

JB的Python之旅-爬取phizhub网站(源码)

jb • 6 年前 • 518 次点击  
阅读 63

JB的Python之旅-爬取phizhub网站(源码)

前言

其实,本篇也是水文,写这篇的原因是,有同学问要源码,既然这与的话,就写一个吧;

上文链接点这里,上文主要介绍这个网站反爬的策略,但是没想到居然有那么多同学看,受宠若惊;

在写源码的时候,遇到一个坑,就是看到时间戳就默认是当前时间戳,结果自己坑自己了,详情请看下面介绍吧;

文章很短且很水,一分钟即可阅读完;

爬取思路

爬取网站地址点这里

多次上滑,接口地址如下:

http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=1&last_time=0&page_size=40

http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=2&last_time=1551141631000&page_size=10

http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=3&last_time=1551138631000&page_size=10

http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=4&last_time=1551120032000&page_size=10
复制代码

首页这里,不停上滑,发现就是pagelast_time在变化; 一个是页码,一个是时间戳;

网站里面有不同的栏目,每个有什么不同?

image.png-21.2kB

多次尝试发现,不同栏目,category会不一样,简单分析下,这个值不是按顺序固定的,好像没办法查?

从程序脚本,肯定是有地方处理的,比如tabname=热门,就返回-1的值,而且,必然是前端处理的,那一起找出来吧;

方法1:

还是老套路,F12,刷新整个页面

image.png-44.9kB

这里面就有一个叫get_tabs的接口,很明显了;

看吧,一目了然了;

image.png-80.6kB

方法2:

如果没有刷新这个页面,是不会发现第一种方法的,在一个页面里面切换不同的tab,是不会再请求get_tabs接口的;

image.png-39.2kB

这种时候,怎么办?没关系,一个一个看吧;

image.png-36.8kB
image.png-73.9kB
image.png-174kB

最终发现,在一个js文件里面有个叫tabSelected的函数,看上去就像有点关系,点击进入看看;

image.png-22kB

点击后进入的是上面的界面,好像没太多关系,简单滑动下?

啧啧啧,就在不远处,就看到这代码了;

image.png-75.2kB

这不就是我们想要的关系表吗?

image.png-35.8kB

手动整理下,如下;

栏目名称 category值
热门 -1
动图 9
图片 4
美女 106
丘比龙 101
搞笑 104
恶搞 105
动漫 7
皮皮虾 107
熊本 102
熊猫人 5

行吧,再分析下json,获取image下的large或small即可;

image.png-54.5kB

然后就啪啪啪的撸码,结果发现,不管怎么爬,永远都是那40张,用postman看了下,的确发现接口每次返回都一模一样,如下:

这是第一次,page=1

image.png-23.1kB

这是第二次,page=2,但是呢,url地址跟第一次的一模一样;

image.png-24.6kB

一开始以为是Bug,但是多次尝试跟看回代码,都没发现啥问题,那就重新正视那4个参数吧;

{'category': -1, 'page': '2', 'last_time': '1551398207276', 'page_size': '10'}


复制代码

categroy是栏目分类,page是页数,page_size是请求图片的数据,唯独不知道last_time是什么;

而jb的代码里面,last_time用的是时间戳;

重新看接口信息:

第一次请求:
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=1&last_time=0&page_size=40

上滑触发第二次请求:
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=2&last_time=1551402631000&page_size=40
复制代码

一开始看到last_time就是时间戳,就没细看,但是现在这个时间戳一看,不对啊,现在是11点,为啥显示9点?那就是说,这个时间戳并非是当前时间戳罗!

image.png-11.4kB

换句话说,这里面肯定是有逻辑吧,行吧,一起看看,还是老套路,看接口js,还是get_data这个,直接搜索last_time,行吧,逻辑都出来了;

image.png-88.1kB
image.png-50.5kB

看吧,last_time就是用上一个接口的最后一个图片的addtime做标记,怪不得会有问题;

var last = photos[count - 1];
last_time = last.addtime;
复制代码

修改下代码看看效果吧~

image.png-66kB

过程输出:

image.png-7.8kB

源码:

由于是临时做的,很不智能,需要的同学二次封装下吧,先简单说说:

# 默认请求一次是40张图片,如果需要修改,找到下方代码直接修改数字即可;
pz_params["page_size"] = "40"

# 分类信息,默认热门,需要爬全部栏目,自己写个数组,for即可,为啥jb不写?因为懒;
category = -1

# 这里是需要爬取的页数,一次40张;
page_number = 5

# 图片下载目录,也可以不用管
dir = "phizhub/remen/"

复制代码

好吧,不墨迹,源码贴上:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
爬取phizhub表情网站
"""
import time
import requests
import hashlib
import json
import re
import os

# 首页链接
pz_index_url = "http://www.phizhub.com/"

# 拼接接口地址
pz_url = pz_index_url+"phiz/get_phiz_list/"

# 请求参数的last_time,第一次是0,后面用上一个接口最后一个图片的addtime做标记
last_time = 0;

# 栏目信息,热门是-1,动图是9,图片是4,美女是106,丘比龙是101,搞笑是104,恶搞是105,动漫是7,皮皮虾是107,熊本是102,熊猫人是5
category = -1

# 请输入需要爬取的页数
page_number = 5

# 图片下载目录
dir = "phizhub/remen/"

# 请求头,F12直接copy过来
pz_headers = {
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Cookie": "SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; gr_user_id=42467006-4ec0-45f7-acdc-91e4060f2262; gr_session_id_a103dce5677f1b74=75095d47-6c68-4ee7-bf81-c2c6be3ece8e; Hm_lvt_fc3add2fc30f38259191ad30ff5813c9=1550714607; gr_session_id_a103dce5677f1b74_75095d47-6c68-4ee7-bf81-c2c6be3ece8e=true; Hm_lpvt_fc3add2fc30f38259191ad30ff5813c9=1550714675",
    "Host": "www.phizhub.com",
    "Pragma": "no-cache",
    "Referer": "http://www.phizhub.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest",
    "Content-Type": "application/x-www-form-urlencoded",
    "sss": "{sss}",
    "timestamp": "{timestamp}"
}

# body
pz_params = {
    "category": category,
    "page": "{page}",
    "last_time": "{last_time}",
    "page_size": "{page_size}",
}

# 获取当前时间的13位时间戳
def get_millistime():
    return str(round(time.time() * 1000))

# 获取sss的值,sss就是phizhub_abc_+当前13位时间戳拼接而成的md5
def get_sss(time):
    str = "phizhub_abc_"+ time
    return md5Encode(str)

# 获取md5
def md5Encode(str):
    m = hashlib.md5()
    m.update(str.encode(encoding='utf-8'))
    return m.hexdigest()


# 干活的地方
def start_job(i):
    global last_time;

    # 页码从1开始算
    set_value(i)
    response = requests.get(pz_url, headers=pz_headers, params=pz_params, verify=False).json()

    # 获取data里面的数量,从而获取对应的图片链接
    count = len(response["data"])
    for page in range(count):
        print('正在下载图片:第%s/%s张,' % (page+1, count))
        download_Image(response["data"][page]["image"]["large"])
        if (page+1 == count):

            last_time = response["data"][page]["addtime"]


# 下载图片
def download_Image(image_link):
    if not os.path.exists(dir):
        os.makedirs(dir)

    filename = get_ImageName(image_link)
    with open(dir + filename, 'wb') as f:
        # 以二进制写入的模式在本地构建新文件
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.32 Safari/537.36',
            'Referer': "http://www.phizhub.com/"}
        f.write(requests.get(image_link, headers=header).content)



# 获取文件名
def get_ImageName(text):
    # http://imagecloud.phizhub.com/1551016041657_b58b2935383a11e9b160186590e027b5.gif
    pattern = re.compile("http://imagecloud.phizhub.com/")
    text = re.sub(pattern, "", text)
    return text



# 赋值
def set_value(i):
    # 赋值时间戳跟sss
    pz_params["page"] = str(i)
    time = get_millistime()
    pz_headers["timestamp"] = time
    pz_headers["sss"] = get_sss(time)
    pz_params["last_time"] = last_time
    pz_params["page_size"] = "40"

if __name__ == '__main__':
    for i in range(1,page_number+1):
        print("现在爬第%s页" % i)
        start_job(i)


复制代码

小结

再次证明这是水文吧,没啥好总结的,就是看到时间戳别想当然是当前时间戳;

谢谢大家~

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/29363
 
518 次点击