虽然期末考试有点坎坷(永远记不住的近代史,裸考概念全不会的C语言,复完就忘得退学分析),怎么说也到了寒假,多少有点时间去学点有意思的东西(预习?预习是不可能的)。上个月底摸了下python记下语法就溜了,然后看到班上的巨佬写得出神入化就想着回来看看爬虫(才不是为了涩图)。
二仪式镇楼(原图: https://i.loli.net/2020/01/15/xOJHqAafWXik3D6.png )
爬虫简介 爬虫,wiki上说是一种用来自动浏览万维网的网络机器人 。个人摸索敲代码爬了一些东西,其实感觉就是一个脚本,模仿用户浏览网站,直接获取网页代码或者和服务器交互,从而得到自己要的资源变色,所以实际上只要会点HTML,JS和C/S的知识,利用下python的几个函数就好。
实践 其一 “有些人看着看着就打开了浏览器”,我当然也有几个小网站,毕竟b站也不是全部番买(18R?怎么可能,我可是良民)。所以就你了 http://www.nicotv.me/ !要上面的云盘链接和提取码就好。
随手点开一部,一眼可以网址的规律,没错,就是数字…
手动去试了试,1到11962都是有效的(虽然后来知道了只有一百来个是有云盘链接的…)。打开F12看看链接对应的标签就可以开始动手写了,懒人就写一个网页的就好(只要搞掂一个加个循环就好,才不是懒)。
Ready perfect!(慎勇语气~~)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import requestsimport reindex=57836 url="http://www.nicotv.club/video/detail/{}.html" .format (index) html=requests.get(url) tree=html.text link=re.findall(r"href=\"https://pan.baidu.com/s/(.+?)\"" ,tree) num=re.findall(r"提取码:(.+?)</a></li>" ,tree) link=link[0 ] num=num[0 ] link="https://pan.baidu.com/s/" +link print (link)print ("提取码:" +num)
后面试了下发现真的有链接的网页比较少,加上要储存在txt,于是就多获取了个标题和”百度网盘下载”选项卡,如果选项卡的list为空就跳过。
其二 云盘资源岂能满足我的※趣!我身体很好,涩图都给我.jpg。然后就对某p站的镜像站下手了,好吧,其实就是不想开粉色小飞机去p站。( https://pixivic.com/ )
输入关键词FGO搜索(老子也是マスター),看网址:
像上面一样用requests获取网页的源代码,发现只是一个框架,并没有任何图片的相关信息,所以应该是动态加载的。打开万能的F12,点进几个JS,在其中一个发现了加载图片的部分。
1 2 3 4 5 6 7 8 9 url = 'https://api.pixivic.com' ; function init ( ) { ajax("get" , url + "/illustrations" , "page=" + page + "&keyword=" + keyword, showlist, true ); } function ajax (method, url, data, callback, flag ) { }
就是用AJAX的方式进行交互,提交的方式是GET,参数有页数page和搜索的关键词keyword。继续解析这个showlist函数,应该就是用来展示图片的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function showlist (data ) { var str = JSON .parse(data).data.illustrations, elem = '' , imgH = 0 , content = document .getElementById("waterfall" ), minIndex; var originalUrl, largeUrl, pre ="https://img.cheerfun.dev:23334/get/" ,originalPre="https://bigimg.cheerfun.dev/get/" ; if (str.length > 0 ) { str.forEach(function (item, index ) { var oDiv = document .createElement("div" ); oDiv.className = "box" ; imgH = Math .ceil(228 * item.height / item.width); originalUrl = item.imageUrls[0 ].original; largeUrl = item.imageUrls[0 ].large.replace('_webp' , '' ); elem = '<a href="' + originalPre + originalUrl + '" alt ="' + item.title + '" class="image" rel="https://www.pixiv.net/member_illust.php?mode=medium&illust_id=' + item.id + '">\<img src ="' + pre + largeUrl + '" height ="' + imgH + '" width="228" alt="' + item.title + '">\</a>' ; elem += item.title.length == 0 ? "" : '<p>' + item.title + '</p>' ; }); } }
其中出现的两个参数pre和originalPre指向的网页路径就很有意思,应该是实现镜像站的功能的,也不管它了,多个字符串组合后形成一个新的链接,然后elem的href使用了,那么应该就是图片的本体的链接。再回到永远滴神F12的Network里抓个JSON包:
发现了一个天坑级别的包(虽然跟着上面的函数可以找到组合前链接的位置,但是真的深…)l链接有4个,p站老油条应该一眼就看出最后一个original是原图(写着英文不是废话吗!!!),试了下直接打开这个链接:
https://i.pximg.net/img-original/img/2016/07/09/00/10/10/57808612_p0.jpg
结果吃了一个403,然后学着上面的函数组合了下变成:
https://bigimg.cheerfun.dev/get/https://i.pximg.net/img-original/img/2016/07/09/00/10/10/57808612_p0.jpg
黑贞老婆出现了(想桃子)!所以下载图片时组合下链接就好。
综合一下:模仿ajax获取json包,然后拿original链接并拼接,最后下载就好。就写两个函数,一个得到可下载链接,一个下载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import requestsimport osfrom urllib.request import urlretrievefrom urllib.parse import quotekeyword='FGO' pre = "https://bigimg.cheerfun.dev/get/" file_path='./img/' +keyword headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36' , } def getLink (i,j,keyword ): url='https://api.pixivic.com/illustrations?keyword={}&page={}' .format (quote(keyword),i) response=requests.get(url,headers) ctx=response.json() link=ctx['data' ]['illustrations' ][j]['imageUrls' ][0 ]['original' ] return pre+link def saveImg (link,file_path ): try : if not os.path.exists(file_path): os.makedirs(file_path) file_name=file_path+'/' +(link.split('/' ))[-1 ] urlretrieve(link,file_name) print ('---下载成功' ) except IOError as e: print ('---文件操作失败:' ,e) except Exception as e: print ('---错误:' ,e) for i in range (5 ): for j in range (30 ): print ('正在处理第{}页,第{}张图...' .format (i+1 ,j+1 )) link=getLink(i+1 ,j,keyword) saveImg(link,file_path) print ('处理完成' )
因为可以开着然后开LOL,打完基本上就下完了,所以也不弄什么多线程了!(也许某种意义上这也是双线程??)。获取链接没有问题,所以连一开始判断链接为空的部分都删了,反而是一开始下载老是出错,下载出错大多数图片下载不完整,想着检验重下就好。对urlretrieve()谷歌了之后发现是可以加个回调函数的,如下:
1 2 3 4 5 6 7 def callback (a,b,c ): '''回调函数 @a: 已经下载的数据块 @b: 数据块的大小 @c: 远程文件的大小 ''' urllib.request.urlretrieve(url, filename, callbak)
用回调函数的第三个参数就可以得到原始文件大小,然后用:
1 fsize = os.path.getsize(filePath)
获取已下载文件大小去对比,如果不对的话就重新下载。但是很麻烦对吧!!于是try…except…大法好,经过多次尝试发现就算是重新下载,一般也很难下载成功,所以干脆抛出错误之后连重新下载也不搞了(只要下的图够多,就可以把损失降低???)。
然后?就没然后了,只是磁盘满了而已(笑~)(借一部私聊?当然没问题)
后语 其实个人不懂python,就连一些语法点也要回去复习,不过靠着谷歌多多少少把功能实现了,至于账号密码登录之类的还没有去碰,因为对C/S其实也没有完全搞清楚,靠谷歌肯定还是能做的,但是没多大意思。
寒假来了,老老实实投了份简历,最后没有被寒假的CTF训练营录取,自己安慰自己说要预习数据结构,要学Java,学更多东西去追上别人,还是有点心灰意冷吧。不过,现在的我还有热情,那就去学吧,也许自学学的零零散散,不像课堂一样系统,但终究是自己的力量。
4-7 补充 大佬的Pixivic 迎来了一次大更新,前后端也开源了,后端用的Java,前端用了Vue.js,对做类似项目比较有参考价值,github地址网站上也写着了(传送门:前端 后端 )。
因为更新了,所以上面请求和拼接链接的方式也有些改变。
https://api.pixivic.com/illustrations?keyword=fgo&page=1&pageSize=30 没有太大变化,更多参数和api可以查看后端文档,然后得到的origin地址去掉 https://i.pximg.net/ 然后把后面的接在 https://original.img.cheerfun.dev/ 后即可(有时候会报403,原因是headers的问题),可以这样解决:
1 2 3 4 5 6 7 8 9 10 11 12 13 import osimport urllibheaders_2 = [ ('referer' ,'https://pixivic.com/illusts/' ), ('User-Agent' , 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36' ), ('accept' ,'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' )] opener = urllib.request.build_opener() opener.addheaders = headers_2 data = opener.open (link) f = open (file_name,'wb' ) f.write(data.read()) f.close()
主要就是给urllib加个headers,注意必须包括referer。
9-8补充 Pixivic 再次更新,需要登录才能查看图片,虽然可以模拟登录继续爬虫,但是还是算了吧