风尘岁月 发表于 2020-7-23 15:50:16

关于多线程保存图片的半异常

上代码{:10_256:}
# 导包
import requests
from time import sleep
import os
import threading
import parsel

if not os.path.exists('image'):
    os.mkdir('image')

# base_url = 'https://anime-pictures.net/pictures/view_posts/0?lang=en'

headers = {
    'User-Agent':
      'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36'
}


def get(url, headers):
    '''请求数据'''
    response = requests.get(url, headers)
    html_data = response.text
    return html_data


def parsel_data(html_data):
    '''筛选数据'''
    selector = parsel.Selector(html_data)
    result_list = selector.xpath('//span[@class="img_block_big"]')

    for result in result_list:
      image_url = result.xpath('./a/picture/source/img/@src').extract_first()
      image_id = result.xpath('./a/picture/source/img/@id').extract_first()

      img_url = 'https:' + image_url# 手动拼url

      all_title = img_url
      img_name = image_id + '.' + img_url.split('.')[-1]

      img_data = requests.get(url=all_title, headers=headers).content

      yield all_title, image_id, img_data, img_name


def save(all_title, image_id, img_data,img_name):
    '''保存数据'''
    try:
      with open('image\\' + img_name, mode='wb') as f:
            print('保存成功:', image_id)
            f.write(img_data)

    except:
      pass
      print('保存失败:', image_id, '(|・ω・` ))')


def start_save(base_url):
    html_data = get(url=base_url, headers=headers)
    for image_data in parsel_data(html_data):
      all_title = image_data# url https://xxxxxxxxxx...
      img_id = image_data# ID
      img_data = image_data# 数据
      img_name = image_data #文件名
      save(all_title=all_title, image_id=img_id, img_data=img_data,img_name = img_name)
      sleep(5)

def main(page):
    for page in range(0, page + 1):
      print('###############正在下载第{}页数据###############'.format(page))
      base_url = 'https://anime-pictures.net/pictures/view_posts/0?lang=en'.format(page)
      if page>0:
            print('休息哈|ू・ω・` )')
            sleep(2)
      my_thread = threading.Thread(target=start_save, args=(base_url,)) #启动多线程
      my_thread.setDaemon(True)
      my_thread.start()
       

if __name__ == '__main__':
    lock = threading.RLock()

    main(6300)






异常,这个异常很奇怪
他一直显示保存成功 但是 实际的文件夹之保存了几张而已{:10_285:}

nahongyan1997 发表于 2020-7-23 23:00:22

可以用主线程专门负责下载数据并用一个全局变量列表保存,创建一个子线程专门用来保存文件。
这样就不会影响下载速度而且因为只用一个线程在保存文件所以不会出现 IO 丢失的现象。

风尘岁月 发表于 2020-7-24 06:24:36

nahongyan1997 发表于 2020-7-23 23:00
可以用主线程专门负责下载数据并用一个全局变量列表保存,创建一个子线程专门用来保存文件。
这样就不会影 ...

我把每一个函数都上过一次锁 结果都没用 说白点就是我不知道他的资源竞争哪里

nahongyan1997 发表于 2020-7-24 07:33:38

除了子线程函数其他函数上锁没有任何用处,推荐按我的方法修改一下程序,不影响下载速度只影响保存速度,也不会慢多少。

风尘岁月 发表于 2020-7-24 07:52:06

nahongyan1997 发表于 2020-7-24 07:33
除了子线程函数其他函数上锁没有任何用处,推荐按我的方法修改一下程序,不影响下载速度只影响保存速度,也 ...

我造诣浅薄 只会使用线程最表层的 还请大佬举个例子(听不懂大佬讲的子线程和IO
啊{:10_277:})

nahongyan1997 发表于 2020-7-24 08:56:17

本帖最后由 nahongyan1997 于 2020-7-24 09:03 编辑

主线程里用 threading 开的线程就是子线程,IO 就是 input,output。

写文件就是 文件 Input,也就是 I 。

nahongyan1997 发表于 2020-7-24 10:56:13

问题已解决,三十秒内下载了上千张图片。
请看代码:
# 导包
import requests
from time import sleep
import os
import threading
import parsel
import random

if not os.path.exists('image'):
    os.mkdir('image')

# base_url = 'https://anime-pictures.net/pictures/view_posts/0?lang=en'

headers = {
    'User-Agent':
      'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36'
}


def get(url, headers):
    '''请求数据'''
    response = requests.get(url, headers)
    html_data = response.text
    return html_data


def parsel_data(html_data):
    '''筛选数据'''
    selector = parsel.Selector(html_data)
    result_list = selector.xpath('//span[@class="img_block_big"]')

    for result in result_list:
      image_url = result.xpath('./a/picture/source/img/@src').extract_first()
      image_id = result.xpath('./a/picture/source/img/@id').extract_first()

      img_url = 'https:' + image_url# 手动拼url

      all_title = img_url
      img_name = image_id + '.' + img_url.split('.')[-1]

      img_data = requests.get(url=all_title, headers=headers).content

      yield all_title, image_id, img_data, img_name


def save(all_title, image_id, img_data,img_name):
    '''保存数据'''
    try:
      with open('image\\' + str(random.randint(0,1000000)) + os.path.splitext(img_name), mode='wb') as f:
            print('保存成功:', image_id)
            f.write(img_data)
    except:
      print('保存失败:', image_id, '(|・ω・` ))')


def start_save(base_url):
    html_data = get(url=base_url, headers=headers)
    for image_data in parsel_data(html_data):
      all_title = image_data# url https://xxxxxxxxxx...
      img_id = image_data# ID
      img_data = image_data# 数据
      img_name = image_data #文件名
      save(all_title=all_title, image_id=img_id, img_data=img_data,img_name = img_name)            

def main(page):
    for page in range(0, page + 1):
      print('###############正在下载第{}页数据###############'.format(page))
      base_url = 'https://anime-pictures.net/pictures/view_posts/0?lang=en'.format(page)
      if page>0:
            print('休息哈|ू・ω・` )')
            sleep(2)

      my_thread = threading.Thread(target=start_save, args=(base_url,)) #启动多线程
      my_thread.setDaemon(True)
      my_thread.start()

      

if __name__ == '__main__':
    lock = threading.RLock()
    main(6300)

页: [1]
查看完整版本: 关于多线程保存图片的半异常