zhaoyanfei52 发表于 2020-10-18 13:18

python全自动无人值守爬取某网站妹子图集

本帖最后由 zhaoyanfei52 于 2020-10-28 22:12 编辑

20号更新
添加了一些判断,修复有的时候会莫名失败!
这次是真的全自动无人值守的采集了!
按图集下载到指定文件夹下,
6162行哪里是指定获取的图集数量!
70行for循环哪里,修改起始和结束的图集编号!
81行修改存储路径!
————————————————————————————————————————————————————————
看了大佬的代码,但是我自己去爬取的时候遇到了些问题!
原帖地址:https://www.52pojie.cn/thread-1260704-1-1.html
感谢大佬的网站!
就干脆自己写了一个!   大家将就用用!我自己爬了半天,才爬了70来个图集,默默的计算了一下全部爬完大概需要十来天(可能我太保守了?)!直接崩溃,多线程又不会!大写的尴尬!
有木有大佬能指点下?

import requests
from lxml import etree
import time
import os
import re

def geturl(url = 'https://www.tujigu.com/'):
    headers = {
      'Accept': '*/*',
      'Accept-Language': 'en-US,en;q=0.8',
      'Cache-Control': 'max-age=0',
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36',
      'Connection': 'keep-alive',
      'Referer': 'http://www.baidu.com/'
            }
    try:
      res = requests.get(url , headers=headers , timeout = 16)#获取源码
      time.sleep(0.8)                                       #等待
      res.encoding = res.apparent_encoding   #防乱码
      xml = etree.HTML(res.text)   #转换成xml格式
      return xml
    except:
      print(f'获取{url}页面失败,已经放弃!')
      return 'error'

def getmaxpage (count):
    maxpage = geturl()
    if maxpage == 'error':
      print('取得最大页失败!')
      return 'max page error'
    else:
      atlnum = maxpage.xpath('//div/ul/li/a/@href')   #取得最新图集链接
      maxnum = atlnum.split('/')    #分割链接,取得最大的图集数量
      if int(count) +6 > int(maxnum[-2]):
            print(f'输入的数值超过现有图集数量,已经把数量更改为现有图集数量{maxnum[-2]}')         # 最大图集数量获取的是首页最新图集的编号!
            print('准备开始>>>>>>>')
            return maxnum[-2]
      else:
            print('准备开始>>>>>>>')
            return count

def getatlname(url):
    atlcode = geturl(url)# 获取页面源码
    if atlcode == 'error':
      print('获取源码失败!')
      return 'code error'
    else:
      atlname = atlcode.xpath('//div[@class="tuji"]/div[@class="weizhi"]/h1/text()')   #获取图集标题
      atlnumber = atlcode.xpath('//div[@class="tuji"]/p/text()')    #获取图集内图片数量
      if atlnumber != []:
            atlnumber1 = atlnumber.split('P')      #分割文本去掉数字后的”p“
            atlnum = atlnumber1.split(' ')      #分割文本 获得图集内图片数量的数字
            atllink = atlcode.xpath('//*[@id="pages"]/a/@href')
            pagenum = atlcode.xpath('//*[@id="pages"]/text()/following-sibling::a/text()')         #子页面总数量
            return atlnum , atlname ,atllink,pagenum[-2]   #把图集内图片数量和图集名称返回
      else:
            print('未获取到图片数量!')
            return 'code error'

total = 0   
# count = input('请输入需要采集的图集数量:')
count = 666666                        #这里写想要采集的数量    更改起始采集图集编号在下面第一个for循环
maxnum = getmaxpage(count)
if maxnum == 'max page error':
    print(f'没有获取到最大页,已经默认输入的{count}为最大页')
    maxnum = int(count)
else:
    maxnum = int(maxnum)

for i in range(765,maxnum+1):               #默认在6开始采集,如果要用别的起始图集编辑更改数字就行,注意最大数!
    atlas = 'https://www.tujigu.com/a/' + str(i) + '/'          #构造url
    # print(tuji)
    atlasinfo = getatlname(atlas)                              #调用函数取得图集名称和图集内图片数量及全部的图集子页面url
    if atlasinfo == 'code error':
      print('获得源码失败!放弃这个图集')
      print(f'url地址:{atlas}')
      continue
    else:
      picname = 1                        #实在不知道咋命名了……随便弄了个变量命名!
      atlname = re.sub('\s' , '' , atlasinfo).replace('/' , '')         #清理一下获取到的图集名,免得命名文件夹的时候出现奇怪的问题
      path = 'D:/tujigu/'+str(atlname)                                 #构造存储路径
      if not os.path.exists(path):               
            os.makedirs(path)                     #如果路径不存在就创建
      print(f'正在采集{atlasinfo},图集编号为【{i}】')
      for j in range(1,int(atlasinfo)+1):
            if j == 1:
                atllink ='https://www.tujigu.com/a/' + str(i) + '/'         #第一页后面加后缀不能访问
            else:
                atllink ='https://www.tujigu.com/a/' + str(i) + '/' + str(j) + '.html'      #构造第二页以后的页面
            picxml = geturl(atllink)
            if picxml == 'error':
                print('获取图片列表失败')
                continue
            else:
                piclist = picxml.xpath('//div[@class="content"]/img/@src')            #获取当前页面下所有的图片列表
                for pic in piclist:
                  piccon = requests.get(pic)                  
                  with open(path + '/' + str(picname) + '.jpg' , 'wb') as f:               #写入图片
                        f.write(piccon.content)
                  total += 1
                  picname += 1
      print(f'【{atlname}采集完成】,本图集一共{atlasinfo}张,当前已经采集总数是{total}张')
print(f'全部采集完毕!')


听了@@rex_the_failure 大佬的建议,改成多进程!用进程池进行进程分配!
import requests
from lxml import etree
import time
import os
import re
import multiprocessing as mp

def geturl(url = 'https://www.tujigu.com/'):
    headers = {
      'Accept': '*/*',
      'Accept-Language': 'en-US,en;q=0.8',
      'Cache-Control': 'max-age=0',
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36',
      'Connection': 'keep-alive',
      'Referer': 'http://www.baidu.com/'
            }
    try:
      res = requests.get(url , headers=headers , timeout = 16)#获取源码
      time.sleep(2)
      res.encoding = res.apparent_encoding   #防乱码
      xml = etree.HTML(res.text)   #转换成xml格式
      return xml
    except:
      print(f'获取{url}页面失败,已经放弃!')
      return 'error'

def getmaxpage (count):
    maxpage = geturl()
    if maxpage == 'error':
      print('取得最大页失败!')
      return 'max page error'
    else:
      atlnum = maxpage.xpath('//div/ul/li/a/@href')   #取得最新图集链接
      maxnum = atlnum.split('/')    #分割链接,取得最大的图集数量
      if int(count) +6 > int(maxnum[-2]):
            print(f'输入的数值超过现有图集数量,已经把数量更改为现有图集数量{maxnum[-2]}')         # 最大图集数量获取的是首页最新图集的编号!
            print('准备开始>>>>>>>')
            return maxnum[-2]
      else:
            print('准备开始>>>>>>>')
            return count

def getatlname(url):
    atlcode = geturl(url)# 获取页面源码
    if atlcode == 'error':
      print('获取源码失败!')
      return 'code error'
    else:
      atlname = atlcode.xpath('//div[@class="tuji"]/div[@class="weizhi"]/h1/text()')   #获取图集标题
      atlnumber = atlcode.xpath('//div[@class="tuji"]/p/text()')    #获取图集内图片数量
      if atlnumber != []:
            atlnumber1 = atlnumber.split('P')      #分割文本去掉数字后的”p“
            atlnum = atlnumber1.split(' ')      #分割文本 获得图集内图片数量的数字
            atllink = atlcode.xpath('//*[@id="pages"]/a/@href')
            pagenum = atlcode.xpath('//*[@id="pages"]/text()/following-sibling::a/text()')         #子页面总数量
            return atlnum , atlname ,atllink,pagenum[-2]   #把图集内图片数量和图集名称返回
      else:
            print('未获取到图片数量!')
            return 'code error'

total = 0   
# count = input('请输入需要采集的图集数量:')
count = 666103                        #这里写想要采集的数量    更改起始采集图集编号在下面倒数第二行里面
maxnum2 = getmaxpage(count)
if maxnum2 == 'max page error':
    print(f'没有获取到最大页,已经默认输入的{count}为最大页')
    maxnum = int(count)
else:
    maxnum = int(maxnum2)

def getpic(i):
    atlas = 'https://www.tujigu.com/a/' + str(i) + '/'          #构造url
    # print(tuji)
    atlasinfo = getatlname(atlas)                              #调用函数取得图集名称和图集内图片数量及全部的图集子页面url
    if atlasinfo == 'code error':
      print('获得源码失败!放弃这个图集')
      print(f'url地址:{atlas}')
      # continue
    else:
      picname = 1                        #实在不知道咋命名了……随便弄了个变量命名!
      atlname = re.sub('\s' , '' , atlasinfo).replace('/' , '')         #清理一下获取到的图集名,免得命名文件夹的时候出现奇怪的问题
      path = 'D:/tujigu/'+str(atlname)                                 #构造存储路径
      if not os.path.exists(path):               
            os.makedirs(path)                     #如果路径不存在就创建
      print(f'正在采集{atlasinfo},图集编号为【{i}】,本图集一共{atlasinfo}张')
      for j in range(1,int(atlasinfo)+1):
            if j == 1:
                atllink ='https://www.tujigu.com/a/' + str(i) + '/'         #第一页后面加后缀不能访问
            else:
                atllink ='https://www.tujigu.com/a/' + str(i) + '/' + str(j) + '.html'      #构造第二页以后的页面
            picxml = geturl(atllink)
            if picxml == 'error':
                print('获取图片列表失败')
                continue
            else:
                piclist = picxml.xpath('//div[@class="content"]/img/@src')            #获取当前页面下所有的图片列表
                for pic in piclist:
                  piccon = requests.get(pic)            
                  with open(path + '/' + str(picname) + '.jpg' , 'wb') as f:               #写入图片
                        f.write(piccon.content)
                  global total
                  total += 1
                  picname += 1
if __name__ == '__main__':
    pool = mp.Pool(processes=8)                   #创建进程池,需要几个就把数字改成几   
    res = pool.map(getpic , (range(6,maxnum+1)))            #启动进程,传入开始图集编号,和需要的图集数量
    print(res)       #没啥用,可以删掉



需要提高采集速度用这个试试!

rex_the_failure 发表于 2020-10-18 13:43

有两种解决方法,一是使用multiprocessing,把循环部分改成多进程。
二是使用twisted异步框架或者其它现成框架,比如scrapy。
python有PIL锁,是伪多线程,不推荐使用多线程。

大懒熊 发表于 2020-10-18 13:29

等待出图。。。

xiaodai_568 发表于 2020-10-18 13:21

妹子图呢 打包的话 评分预计更多

zhaoyanfei52 发表于 2020-10-18 13:24

xiaodai_568 发表于 2020-10-18 13:21
妹子图呢 打包的话 评分预计更多

还没爬完呢……{:301_971:}

hacksz 发表于 2020-10-18 13:31

我就来学习学习

q13467982 发表于 2020-10-18 13:37

学习也看不懂{:1_937:}

列明 发表于 2020-10-18 13:58

你没计算你的硬盘够不够?

zhaoyanfei52 发表于 2020-10-18 14:08

rex_the_failure 发表于 2020-10-18 13:43
有两种解决方法,一是使用multiprocessing,把循环部分改成多进程。
二是使用twisted异步框架或者其它现成 ...

谢谢!考虑过使用多线程,但是……涉及到知识盲区了……正在恶补!{:301_999:}

zhaoyanfei52 发表于 2020-10-18 14:09

列明 发表于 2020-10-18 13:58
你没计算你的硬盘够不够?

扎心了……老铁!
页: [1] 2 3 4 5
查看完整版本: python全自动无人值守爬取某网站妹子图集