4028574 发表于 2018-6-2 12:11

[Python]多线程爬去美女图片实战加抓包分析

本帖最后由 wushaominkk 于 2018-6-2 17:06 编辑

昨天发了一个爬去影视网站的帖子 看到很多有很多朋友蛮喜欢的
正好又看到一个帖子上二楼说 图片的地址随机化了 不能直接取


才有了此贴本帖的目的是
原贴中的方法是方法是访问每个页面去取得这个图片的地址 这样是很浪费性能的 本帖是通过分析js代码从中找到他交互的地址得到他的返回值 自己构造图片地址 实现下载
这样的好处就是 我们不需要为了下载每个图片都去访问一遍他们的页面只需要访问第一页获得这个图片的前段的url 后面的图片地址自己构造就都可以下载了
其实本帖就是对原贴的升级和改进而已

原贴在此:https://www.52pojie.cn/thread-691064-1-1.html
原贴中使用的是多进程 本帖采用多线程的方式因为有linux开发经验的朋友 应该知道win系统是没有多进程的概念的 多进程是linux的概念
鉴于很多朋友是在win平台下运行的 所以这里采用多线程的方法进行操作


第一步进入网站www.mmjpg.com进入之后可以看到很多图片这里打开浏览器只带的开发者模式我相信这个大家应该都会了就不多说了 然后点击左上角的

点击其中一个图片 就可以看到这个图片的地址了 然后使用xpath语法来获得这个图片的href那么开始至于xpath的语法 大家可以进入百度里面有详细介绍 这里就不多言了//div[@class='pic']/ul/li/a/@href   这样就获得了第一页的所有的图片的链接


第二步或者单个链接中的所有图片的下载地址这里随便点击一张图片进入之后照例按下F12 选择图片这里需要获得是图片的名称 和 所有图片的链接

//div[@class='article']/h2/text()   图片的名称


然后来取图片的链接这里就是关键了 首先我们按下F5刷新一下因为大家知道如果这个页面需要用到js那么必须要加载那么抓包的话 是可以看到他加载的js的

这里看到他加载了一个content.js 那么我们直接进去分析他就可以了但是鉴于可能有的朋友不太知道js的语法那么告诉大家一个偷懒的方法首先先点击clear 清理一下因为这个图片进入之后可以点击全部图片那么正常的情况下应该是你点击全部图片之后他会发包 那么我只要知道他发的什么包 发包时的参数 然后自己去构造这个发包的请求就可以了那么当我们点击全部图片之后会看到如下内容

大家看到 他会发送一个data.php的请求而且后面的指示是content.js中47行发出的 所以跟我们上面分析的一样 那么我们看看 他的返回

他返回了一串看不懂的东西其实稍微懂点的人应该能明白了 这里返回的是图片的随机的名称因为我们当前在第一张图那么我们看下图片的地址

有没有发现什么一样的东西
所有的地址中有固定的值 比如第一个是 1ifn.jpg第二个是2ig6
也就是说这个名称中 第一个字符是图片序号 第二字符是固定的i那么后两位就是上面返回的值第一个是fn 第二个是g6
那么到此图片的所有名称我们已经拿到了 那么就可以去下载了


那么来分析一下参数大家能看到 他需要两个参数
第一个是id   
第二个是 page

这个就是id至于page 那个应该是请求的显示页面 给最大就行 他自己的js中就写的8899 说明这个应该是最大了 所以这个参数中只有一个id是需要的 其他的都不需要   


这个data.php 请求是get的值 在浏览器中直接访问是不返回的 所以他可能检测了请求头中的某些值 我们只需要在请求中加上就可以了

好了 那么分析已经完成 下面开始上代码
Python环境: python2.7
模块用到 requests   lxml

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from threading import *
import requests
from lxml import etree
import os

gHeads = {
    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
}

nMaxThread = 3
ThreadLock = BoundedSemaphore(nMaxThread)

class PhotoThread(Thread):
    def __init__(self,url):
      Thread.__init__(self)
      self.url = url

    def run(self):
      try:
            PhotoName,firsturl,uid = self.GetPhotoInfo(self.url)
            if uid :
                secName = self.GetPhotoRandomName(uid)
                if secName:
                  self.DownloadPhoto(firsturl,secName,uid,PhotoName)
      finally:
            ThreadLock.release()

    def GetPhotoInfo(self,url):
      heads = {
            "Host": "www.mmjpg.com",
            "Referer": "http://www.mmjpg.com/"
      }
      heads.update(gHeads)
      try:
            html = requests.get(url,headers=heads)
            html.encoding="utf-8"
            xmlContent = etree.HTML(html.text)
            PhotoName = xmlContent.xpath("//div[@class='article']/h2/text()")
            imgUrl = xmlContent.xpath("//div[@class='content']/a/img/@src")
            firstImgUrl = imgUrl[:imgUrl.rfind("/")]
            uid = firstImgUrl
            return PhotoName,firstImgUrl,uid
      except:
            return None,None

    def GetPhotoRandomName(self,uid):
      heads = {
            "Host":"www.mmjpg.com",
            "Referer":"http://www.mmjpg.com/mm/%s"%(uid)
      }
      heads.update(gHeads)
      try:
            html = requests.get("http://www.mmjpg.com/data.php?id=%s&page=8999"%(uid),headers=heads).text
            retName = html.split(",")
            return retName
      except:
            return None

    def DownloadPhoto(self,firstUrl,randomName,uid,photoName):
      heads = {
            "Host": "img.mmjpg.com",
            "Referer":"http://www.mmjpg.com/mm/%s"%(uid)
      }
      heads.update(gHeads)
      savePath = "./photo/%s"%photoName
      if not os.path.exists(savePath):
            os.makedirs(savePath)
      for i in xrange(len(randomName)):
            url = "%s/%si%s.jpg"%(firstUrl,i+1,randomName)
            html = requests.get(url,headers=heads)
            if html.status_code == 200 :
                with open("%s/%d.jpg"%(savePath,i+1),"wb") as f:
                  print "Download : %s/%d.jpg"%(photoName,i+1)
                  f.write(html.content)
                  #sleep(0.2)
            else:
                return None

def main():
    nMaxPage = int(raw_input("请输入需要几页: "))
    for i in xrange(nMaxPage):
      url = "http://www.mmjpg.com/" if i == 0 else "http://www.mmjpg.com/home/%d"%(i+1)
      html = requests.get(url,headers=gHeads).text
      xmlContent = etree.HTML(html)
      urlList = xmlContent.xpath("//div[@class='pic']/ul/li/a/@href")
      for url in urlList:
            ThreadLock.acquire()
            t = PhotoThread(url)
            t.start()


if __name__ == '__main__':
    main()

代码中使用的是3条线程同时操作 可以自己修改nMaxThread 这个参数 来实现更多条线程下载的时候最好加上延时 这样不至于被检测到
最后附上成品图


请看官看请备好纸巾以免你懂的{:301_988:}



4028574 发表于 2018-6-2 16:23

顾修与 发表于 2018-6-2 15:03
我看过那篇文章 后边不是还要爬一次微信 qq 微博吗?

我只是改进了那篇帖子而已    我又没承诺要爬微信 QQ 微博呀只不过到是可以一试哦哪天看看 有机会 发个爬微博的或者爬抖音视频{:301_986:}

顾修与 发表于 2018-6-2 16:34

4028574 发表于 2018-6-2 16:23
我只是改进了那篇帖子而已    我又没承诺要爬微信 QQ 微博呀只不过到是可以一试哦哪天看看 有机会 发 ...

有想法 爬的时候记得叫我
嗯。。。爬完叫我也行
云盘还有一个T 放心爬

li645944229 发表于 2018-6-2 12:33

就喜欢教程,有空多放些……

余老 发表于 2018-6-2 12:36

那么你的成果呢?我要实物,过程可以忽略{:301_997:}

Zhang.J 发表于 2018-6-2 12:42

感谢分享

cosxiaobaitu 发表于 2018-6-2 12:44

还有这种操作?我是很服气的收藏了

jacky520510 发表于 2018-6-2 12:51

宅男的福音,多多益善{:301_995:}

零零零零 发表于 2018-6-2 13:27

啧啧   这个是神器啊

河东奇 发表于 2018-6-2 13:47

好的学习了,虽然我听的有点小懵逼

suantia 发表于 2018-6-2 13:55

学习学习了这个完全是高后

otho 发表于 2018-6-2 14:30

谢谢楼主分享
页: [1] 2 3
查看完整版本: [Python]多线程爬去美女图片实战加抓包分析