前言
其实,本篇也是水文,写这篇的原因是,有同学问要源码,既然这与的话,就写一个吧;
上文链接点,上文主要介绍这个网站反爬的策略,但是没想到居然有那么多同学看,受宠若惊;
在写源码的时候,遇到一个坑,就是看到时间戳就默认是当前时间戳,结果自己坑自己了,详情请看下面介绍吧;
文章很短且很水,一分钟即可阅读完;
爬取思路
爬取网站地址点;
多次上滑,接口地址如下:
http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=1&last_time=0&page_size=40http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=2&last_time=1551141631000&page_size=10http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=3&last_time=1551138631000&page_size=10http://www.phizhub.com/phiz/get_phiz_list/?category=-1&page=4&last_time=1551120032000&page_size=10复制代码
首页这里,不停上滑,发现就是page
跟last_time
在变化; 一个是页码,一个是时间戳;
网站里面有不同的栏目,每个有什么不同?
多次尝试发现,不同栏目,category
会不一样,简单分析下,这个值不是按顺序固定的,好像没办法查?
从程序脚本,肯定是有地方处理的,比如tabname=热门
,就返回-1
的值,而且,必然是前端处理的,那一起找出来吧;
方法1:
还是老套路,F12,刷新整个页面
;
这里面就有一个叫get_tabs
的接口,很明显了;
看吧,一目了然了;
方法2:
如果没有刷新这个页面,是不会发现第一种方法的,在一个页面里面切换不同的tab,是不会再请求get_tabs
接口的;
这种时候,怎么办?没关系,一个一个看吧;
最终发现,在一个js文件里面有个叫tabSelected
的函数,看上去就像有点关系,点击进入看看;
点击后进入的是上面的界面,好像没太多关系,简单滑动下?
啧啧啧,就在不远处,就看到这代码了;
这不就是我们想要的关系表吗?
手动整理下,如下;
栏目名称 | category值 |
---|---|
热门 | -1 |
动图 | 9 |
图片 | 4 |
美女 | 106 |
丘比龙 | 101 |
搞笑 | 104 |
恶搞 | 105 |
动漫 | 7 |
皮皮虾 | 107 |
熊本 | 102 |
熊猫人 | 5 |
行吧,再分析下json,获取image下的large或small即可;
然后就啪啪啪的撸码,结果发现,不管怎么爬,永远都是那40张,用postman看了下,的确发现接口每次返回都一模一样,如下:
这是第一次,page=1
;
这是第二次,page=2
,但是呢,url地址跟第一次的一模一样;
一开始以为是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点?那就是说,这个时间戳并非是当前时间戳罗!
换句话说,这里面肯定是有逻辑吧,行吧,一起看看,还是老套路,看接口js,还是get_data
这个,直接搜索last_time
,行吧,逻辑都出来了;
看吧,last_time
就是用上一个接口的最后一个图片的addtime
做标记,怪不得会有问题;
var last = photos[count - 1];last_time = last.addtime;复制代码
修改下代码看看效果吧~
过程输出:
源码:
由于是临时做的,很不智能,需要的同学二次封装下吧,先简单说说:
# 默认请求一次是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 timeimport requestsimport hashlibimport jsonimport reimport 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,熊猫人是5category = -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}"}# bodypz_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位时间戳拼接而成的md5def get_sss(time): str = "phizhub_abc_"+ time return md5Encode(str)# 获取md5def 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)复制代码
小结
再次证明这是水文吧,没啥好总结的,就是看到时间戳别想当然是当前时间戳;
谢谢大家~