鱼C论坛

 找回密码
 立即注册
查看: 1352|回复: 3

[作品展示] 爬取煎蛋ooxx图片测试代码(对小甲鱼老师课程代码的魔改)

[复制链接]
发表于 2018-7-21 00:57:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 EzioA 于 2018-7-21 10:57 编辑

昨天看到小甲鱼老师这一讲的内容,自己尝试,发现完全行不通了。审查jandan.net/ooxx/的网页源代码,发现源代码中并没有真正的图片地址,而是浏览器调用了JS对源代码进行了修改,在F12中才能看到源地址。
查了很多资料,跟踪请求包,手动分析了调用的JS的逻辑,把实际使用的JS分离出来,通过execjs模块来执行JS代码。
可用代码如下:
  1. from bs4 import BeautifulSoup
  2. import urllib.request
  3. import urllib.parse
  4. import execjs
  5. import time
  6. import multiprocessing as mp

  7. headers = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
  8. url = 'http://jiandan.net/ooxx'
  9. ##processings = []
  10. ##current_page = 0      在多进程执行中,子进程使用这种定义在主进程中的全局变量会出现奇怪的问题(fork出子进程时生成的全局变量怕不是直接从代码段拷贝过去了 XD)

  11. def main():
  12.         t1 = time.time()
  13. ##        for _offset in range(10):
  14. ##                processing = mp.Process(target = func, args = (soup, opener, _offset, current_page), name = 'T'+str(_offset))
  15. ##                processings.append(processing)
  16. ##                processing.start()
  17. ##        for _offset in range(10):
  18. ##                processings[_offset].join()

  19. ##        for _ in range(4):
  20. ##                processings[_].join()
  21. ##                print("hello, world")
  22.         pool = mp.Pool(4)
  23.         for _offset in range(10):
  24.                 pool.apply_async(func = task, args = (_offset,))
  25.         pool.close()
  26.         pool.join()
  27. ##        pool.map(func, args)
  28. ##        for each in threads:
  29. ##                each.start()
  30. ##                each.join()
  31. ##        func(soup, opener)
  32.         temp = time.time() - t1
  33.         line = "煎蛋进程池爬10页时间:"+str(temp)
  34.         with open("jandan_pools.txt", 'w') as txt:
  35.                 txt.write(line)
  36.         
  37. def task(_offset):
  38.         global headers, url     ##由于这两个变量我们不会进行修改,不存在fork出的进程与父全局变量之间的问题
  39.         opener = urllib.request.build_opener()
  40.         opener.add_handler = [headers]
  41.         html = opener.open(url).read()
  42.         soup = BeautifulSoup(html, 'html5lib')
  43.         current_page = int(soup.find(class_ = 'current-comment-page').text[1:-1])
  44.         
  45.         my_page = current_page - _offset
  46.         html = opener.open(''.join([url, '/page-', str(my_page)])).read()
  47.         print("Open")
  48.         soup = BeautifulSoup(html, 'html5lib')
  49.         ol = soup.find(name = 'ol', class_ = "commentlist")
  50.         li = ol.find_all(name = 'li')
  51.         count = 0

  52.         for each in li:
  53.                 if each.has_attr('id') and not each.has_attr('class'):
  54.                         img = each.find(name = 'img')
  55.                         img_hash = img.next_sibling.text

  56.                         ##调用JS代码
  57.                         with open("./func1.js", encoding='UTF-8') as f:
  58.                                 line = f.readline()
  59.                                 func = ''
  60.                                 while line:
  61.                                         func += line
  62.                                         line = f.readline()
  63.                         ctx = execjs.compile(func)
  64.                         img_url = (ctx.call("jandan_load_img", img_hash))
  65.                         
  66.                         with open(''.join([r"C:/Users/ezio7/Desktop/img/", str(_offset), '_', str(count), img_url[-4:]]), 'wb') as f:
  67.                                 print("T"+str(_offset))
  68.                                 f.write(opener.open(''.join(['http:', img_url])).read())
  69.                                 count += 1
  70.         return 1
  71.                
  72.         
  73. if __name__ == "__main__":
  74.         main()
复制代码

这是多线程版本的,爬取10个页面用时80~90秒。

  1. from bs4 import BeautifulSoup
  2. import urllib.request
  3. import urllib.parse
  4. import execjs
  5. import time
  6. import multiprocessing as mp
  7. import threading

  8. headers = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
  9. url = 'http://jiandan.net/ooxx'
  10. ##threads = []
  11. ##lock = threading.Lock()

  12. def main():
  13. ##        for _ in range(4):
  14. ##                thread = threading.Thread(target = func, args = (soup, opener), name = 'T'+str(_))
  15. ##                threads.append(thread)
  16.         t1 = time.time()
  17. ##        for each in threads:
  18. ##                each.start()
  19. ##                each.join()
  20.         func()
  21.         temp = time.time() - t1
  22.         line = "煎蛋单进程爬10页时间:"+str(temp)
  23.         with open("jandan_time.txt", 'w') as txt:
  24.                 txt.write(line)
  25.         
  26. def func():
  27.         global headers, url
  28.         count = 0
  29.         page = 0
  30.         opener = urllib.request.build_opener()
  31.         opener.add_handler = [headers]
  32.         html = opener.open(url).read()
  33.         soup = BeautifulSoup(html, 'html5lib')
  34.         current_page = int(soup.find(class_ = 'current-comment-page').text[1:-1])
  35.         
  36. ##        lock.acquire()
  37.         while page < 10:
  38.                 ol = soup.find(name = 'ol', class_ = "commentlist")
  39.                 li = ol.find_all(name = 'li')
  40.                 for each in li:
  41.                         if each.has_attr('id') and not each.has_attr('class'):
  42.                                 img = each.find(name = 'img')
  43.                                 img_hash = img.next_sibling.text

  44.                                 ##调用JS代码
  45.                                 with open("./func1.js", encoding='UTF-8') as f:
  46.                                         line = f.readline()
  47.                                         func = ''
  48.                                         while line:
  49.                                                 func += line
  50.                                                 line = f.readline()
  51.                                 ctx = execjs.compile(func)
  52.                                 img_url = (ctx.call("jandan_load_img", img_hash))
  53. ##                                print(img_url)

  54.                                 with open(''.join([r"C:/Users/ezio7/Desktop/img", '/_', str(count), img_url[-4:]]), 'wb') as f:
  55.                                         f.write(opener.open(''.join(['http:', img_url])).read())
  56.                                         count += 1
  57.                 current_page -= 1
  58.                 page += 1
  59.                 print(current_page, '\t', page)
  60.                 html = opener.open(''.join([url, '/page-', str(current_page)])).read()
  61.                 soup = BeautifulSoup(html, 'html5lib')
  62. ##        lock.release()
  63.         
  64. if __name__ == "__main__":
  65.         main()
复制代码

这是单进程版本的,用时130+秒。

分析修改后的JS代码见附件,其中为了取代原JS代码中的某些外部函数,引入了相同功能的函数。
完全使用暴力爬取,宕掉的可能性极高,只是为了测试多进程和普通爬取的速率差别(代理和延迟设置太麻烦 XD)
py文件和js文件请放在同一路径下,下载路径请自行修改。


煎蛋妹子OOXX图片爬取测试代码.zip (8.1 KB, 下载次数: 26)

珍惜每一个福利网站,请小心使用暴力爬虫

另外,不知道为什么别的爬虫是I/O密集型,用多线程效果蛮好的,而我的这段爬虫是计算密集型的。因为使用了execjs的缘故?听说这个模块挺慢的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-8-20 20:53:40 From FishC Mobile | 显示全部楼层
感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-8-25 12:34:04 | 显示全部楼层
原来问题在这
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-31 13:06:34 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-19 21:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表