Python tải xuống tất cả các tệp từ url

Điều này có thể tăng tốc đáng kể quá trình tải xuống so với việc tải xuống từng tệp một cách tuần tự.

Trong hướng dẫn này, bạn sẽ khám phá cách tải xuống đồng thời nhiều tệp từ internet bằng các luồng trong Python

Sau khi hoàn thành hướng dẫn này, bạn sẽ biết

  • Cách tải xuống từng tệp từ internet bằng Python và tốc độ của nó có thể chậm như thế nào
  • Cách sử dụng ThreadPoolExecutor để quản lý nhóm luồng công nhân
  • Cách cập nhật mã để tải xuống nhiều tệp cùng một lúc và tăng tốc đáng kể quá trình

Hãy đi sâu vào

Mục lục

  • Cách tải xuống tệp từ Internet (từ từ)
    • Tải xuống tệp URL
    • Phân tích cú pháp HTML cho tệp để tải xuống
    • Lưu tải xuống tệp cục bộ
    • Phối hợp quá trình tải xuống
    • Hoàn thành ví dụ
  • Cách tạo một nhóm chủ đề công nhân với ThreadPoolExecutor
    • Tạo nhóm chủ đề
    • Gửi nhiệm vụ đến Thread Pool
    • Nhận kết quả khi hoàn thành nhiệm vụ
    • Tắt nhóm chủ đề
  • Cách tải xuống nhiều tệp đồng thời
  • Tiện ích mở rộng
  • Đọc thêm
  • mang đi

Cách tải xuống tệp từ Internet (từ từ)

Tải xuống tệp từ internet là một nhiệm vụ phổ biến

Ví dụ

  • Bạn có thể cần tải xuống tất cả các tài liệu để tham khảo ngoại tuyến
  • Bạn có thể cần phải tạo một bản sao lưu của tất cả. tệp zip cho một dự án
  • Bạn có thể cần một bản sao lưu trữ tệp cục bộ

Nếu bạn không biết cách viết mã, thì bạn có thể giải quyết vấn đề này bằng cách tải trang web trong trình duyệt, sau đó nhấp lần lượt vào từng tệp để lưu vào ổ cứng của bạn

Đối với nhiều tệp, quá trình này có thể mất nhiều thời gian để nhấp vào từng tệp trước tiên và sau đó đợi tất cả các lượt tải xuống hoàn tất

Rất may, chúng tôi là nhà phát triển, vì vậy chúng tôi có thể viết một tập lệnh để trước tiên khám phá tất cả các tệp trên trang web để tải xuống, sau đó tải xuống và lưu trữ tất cả chúng cục bộ

Một số ví dụ về các trang web liệt kê các tệp mà chúng tôi có thể tải xuống các tệp bao gồm

  • Tất cả các phiên bản của thư viện Beautiful Soup phiên bản 4
  • Tất cả các sửa đổi bot cho trò chơi máy tính Quake 1
  • Tất cả tài liệu cho Python phiên bản 3. 9. 7

Trong các ví dụ này, có một trang web HTML duy nhất cung cấp các liên kết tương đối đến các tệp được lưu trữ cục bộ

Lý tưởng nhất là trang web sẽ liên kết đến nhiều tệp nhỏ hoặc có kích thước khiêm tốn và bản thân máy chủ sẽ cho phép nhiều kết nối từ mỗi máy khách

Điều này có thể không phải lúc nào cũng đúng vì hầu hết các máy chủ đều giới hạn số lượng kết nối trên mỗi máy khách là 10 hoặc thậm chí 1 để ngăn chặn các cuộc tấn công từ chối dịch vụ

Chúng tôi có thể phát triển một chương trình để tải xuống từng tệp một

Có một vài phần của chương trình này;

  1. Tải xuống tệp URL
  2. Phân tích cú pháp HTML cho tệp để tải xuống
  3. Lưu tải xuống tệp cục bộ
  4. Phối hợp quá trình tải xuống
  5. Hoàn thành ví dụ

Hãy xem lần lượt từng phần

Ghi chú. chúng tôi sẽ chỉ thực hiện xử lý lỗi cơ bản nhất. Nếu bạn thay đổi URL mục tiêu, bạn có thể cần điều chỉnh mã cho các chi tiết cụ thể của HTML và các tệp bạn muốn tải xuống

Tải xuống tệp URL

Bước đầu tiên là tải xuống một tệp được chỉ định bởi một URL

Có nhiều cách để tải xuống một URL trong Python. Trong trường hợp này, chúng ta sẽ sử dụng hàm urlopen() để mở . read() function to download the contents of the file into memory.

Để đảm bảo kết nối tự động đóng sau khi chúng tôi tải xuống xong, chúng tôi sẽ sử dụng trình quản lý ngữ cảnh, e. g. từ khóa với .

Bạn có thể tìm hiểu thêm về cách mở và đọc từ các kết nối URL trong API Python tại đây

  • urllib. yêu cầu – Thư viện mở rộng để mở URL

Hàm download_url() bên dưới thực hiện điều này, .

1

2

3

4

5

6

# tải tệp từ một URL, trả về nội dung của tệp đã tải xuống

def download_url(đường dẫn url):

    # mở kết nối với máy chủ

    với urlopen(đường dẫn url) as connection:

        # đọc nội dung của url dưới dạng byte và gửi lại

        trả lại kết nối. đọc()

Chúng tôi sẽ sử dụng chức năng này để tải xuống trang HTML liệt kê các tệp và tải xuống nội dung của từng tệp được liệt kê

Một cải tiến về chức năng này là thêm thời gian chờ trên kết nối, có thể sau vài giây. Điều này sẽ đưa ra một ngoại lệ nếu máy chủ không phản hồi và là một cách thực hành tốt khi mở kết nối với máy chủ từ xa

Phân tích cú pháp HTML cho tệp để tải xuống

Khi trang HTML của các URL được tải xuống, chúng tôi phải phân tích cú pháp trang đó và trích xuất tất cả các liên kết đến tệp

Tôi khuyên dùng thư viện BeautifulSoup Python bất cứ lúc nào tài liệu HTML cần được phân tích cú pháp

Nếu bạn chưa quen với BeautifulSoup, bạn có thể cài đặt nó dễ dàng bằng trình quản lý gói Python của mình, chẳng hạn như pip

1

cài đặt pip beautifulsoup4

Đầu tiên, chúng ta phải giải mã dữ liệu thô được tải xuống thành văn bản ASCII

Điều này có thể đạt được bằng cách gọi decode() function on the string of raw data and specifying a standard text format, such as UTF-8.

1

2

3

.. .

# giải mã nội dung được cung cấp dưới dạng văn bản ascii

html = nội dung. giải mã('utf-8')

Tiếp theo, chúng ta có thể phân tích cú pháp văn bản của tài liệu HTML bằng BeautifulSoup bằng trình phân tích cú pháp mặc định

Bạn nên sử dụng trình phân tích cú pháp tinh vi hơn hoạt động giống nhau trên tất cả các nền tảng, nhưng trong trường hợp này, sẽ sử dụng trình phân tích cú pháp mặc định vì nó không yêu cầu bạn cài đặt thêm bất kỳ thứ gì

1

2

3

.. .

# phân tích cú pháp tài liệu tốt nhất có thể

súp = Súp đẹp(html, 'html.parser')

Sau đó, chúng tôi có thể truy xuất tất cả thẻ HTML từ tài liệu vì những thẻ này sẽ chứa URL cho các tệp chúng tôi .

1

2

3

.. .

# find all all of the tags in the document

tags = súp. find_all('a')

Sau đó, chúng tôi có thể duyệt qua tất cả các thẻ được tìm thấy và truy xuất nội dung của thuộc tính href trên mỗi thẻ, e. g. lấy các liên kết đến các tệp từ mỗi thẻ. Nếu thẻ không chứa thuộc tính href (có thể là số lẻ, e. g. một liên kết neo), thì chúng ta sẽ hướng dẫn hàm trả về None .

Điều này có thể nằm trong phần hiểu danh sách, cung cấp cho chúng tôi danh sách các URL tới các tệp để tải xuống và có thể một số

Không cógiá trị

1

2

3

.. .

# nhận tất cả các giá trị href (liên kết) hoặc Không có nếu không có (không chắc)

return [t. lấy('href', None) for t in atags]

Liên kết tất cả những thứ này lại với nhau, get_urls_from_html() .

1

2

3

4

5

6

7

8

9

10

# decode downloaded html and extract all links

def get_urls_from_html(nội dung):

    # giải mã nội dung được cung cấp dưới dạng văn bản ascii

    html = nội dung. giải mã('utf-8')

    # phân tích cú pháp tài liệu tốt nhất có thể

    súp = Súp đẹp(html, 'html.parser')

    # tìm tất cả

    tags = súp. find_all('a')

    # nhận tất cả các giá trị href (liên kết) hoặc Không có nếu không có (không chắc)

    return [t. lấy('href', None) for t in atags]

Chúng tôi sẽ sử dụng chức năng này để trích xuất tất cả các tệp từ trang HTML liệt kê các tệp chúng tôi muốn tải xuống

Lưu tải xuống tệp cục bộ

Chúng tôi biết cách tải xuống tệp và nhận liên kết từ HTML. Một phần quan trọng khác mà chúng tôi cần là lưu các URL đã tải xuống vào các tệp cục bộ

Điều này có thể được thực hiện bằng cách sử dụng mở() .

Chúng tôi sẽ mở tệp ở chế độ ghi và định dạng nhị phân, vì chúng tôi có thể sẽ tải xuống. tệp zip hoặc tương tự

Giống như với việc tải xuống các URL ở trên, chúng tôi sẽ sử dụng trình quản lý ngữ cảnh (từ khóa với ) để đảm bảo rằng kết nối tới tệp đã được đóng .

Hàm save_file() bên dưới thực hiện điều này, .

1

2

3

4

5

6

# lưu nội dung được cung cấp vào đường dẫn cục bộ

def save_file(đường dẫn, data):

    # mở tệp cục bộ để ghi

    với mở(đường dẫn, 'wb') as file:

        # ghi tất cả dữ liệu được cung cấp vào tệp

        tệp. ghi(dữ liệu)

Bạn có thể muốn thêm xử lý lỗi ở đây, chẳng hạn như không ghi được hoặc trường hợp tệp đã tồn tại cục bộ

Chúng ta cần thực hiện một số công việc để có thể sử dụng chức năng này

Ví dụ: chúng tôi cần kiểm tra xem chúng tôi có liên kết nào từ thuộc tính href không (rằng đó không phải là None ) và URL đó . g. có một. nén hoặc. phần mở rộng gz). Đây là một số kiểm tra hoặc lọc lỗi cơ bản đối với các loại URL mà chúng tôi muốn tải xuống.

1

2

3

4

5

6

7

.. .

# bỏ qua url xấu hoặc tên tệp xấu

nếu liên kết Không có hoặc link == '../'.

    trả lại

# kiểm tra không có phần mở rộng tập tin

nếu không (liên kết[-4] == '.' hoặc liên kết[- . '] == '.' ).

    trả lại

Các trang HTML liệt kê các tệp thường bao gồm các liên kết tương đối thay vì liên kết tuyệt đối

Tức là, các liên kết đến các tệp được tải xuống sẽ liên quan đến tệp HTML. Chúng ta phải chuyển đổi chúng thành liên kết tuyệt đối (với http. //. ở phía trước) để có thể tải xuống tệp.

Chúng ta có thể sử dụng chức năng urljoin() từ . Mô-đun urllib.phân tích cú pháp để chuyển đổi bất kỳ URL tương đối nào thành URL tuyệt đối để chúng tôi có thể tải tệp xuống.

1

2

3

.. .

# chuyển đổi liên kết tương đối thành liên kết tuyệt đối

vô lý = urljoin(url, link)

Sau đó, bạn có thể tải xuống URL tuyệt đối bằng cách sử dụng download_url() function developed above.

1

2

3

.. .

# tải xuống nội dung của tệp

dữ liệu = download_url(bất ngờ)

Tiếp theo, chúng ta cần xác định tên của tệp từ URL mà chúng ta sẽ lưu cục bộ. Điều này có thể đạt được bằng cách sử dụng hàm tên cơ sở() từ os.đường dẫn mô-đun.

1

2

3

.. .

# lấy tên tệp

tên tệp = tên cơ sở(lố)

Sau đó, chúng ta có thể xác định đường dẫn cục bộ để lưu tệp bằng cách kết hợp đường dẫn thư mục cục bộ với tên tệp. Hàm tham gia() từ hệ điều hành. mô-đun đường dẫn sẽ thực hiện việc này cho chúng tôi một cách chính xác dựa trên nền tảng của chúng tôi (Unix, Windows, MacOS).

1

2

3

.. .

# xây dựng đường dẫn đầu ra

đường ra = tham gia(đường, filename)

Bây giờ chúng tôi có đủ thông tin để lưu tệp bằng cách gọi save_file() function.

1

2

3

.. .

# lưu vào tập tin

save_file(đường ra, dữ liệu)

Hàm  download_url_to_file() bên dưới liên kết tất cả . Nó tải xuống URL, lưu cục bộ dưới dạng tệp và trả về liên kết tương đối và đường dẫn tệp cục bộ trong một bộ dữ liệu.

Nếu tệp không được lưu, chúng tôi trả về một bộ chỉ với URL tương đối và Không có cho đường dẫn cục bộ

Chúng tôi chọn trả lại một số thông tin từ chức năng này để người gọi có thể báo cáo tiến độ về việc tải xuống từng tệp thành công hay thất bại

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# tải một tệp xuống thư mục cục bộ

def download_url_to_file(url, link, path):

    # bỏ qua url không hợp lệ hoặc tên tệp không hợp lệ

    nếu liên kết Không có or link == '../'.

        trả lại (liên kết, None)

    # kiểm tra xem không có phần mở rộng tệp nào

    nếu không (liên kết[-4] == '.' hoặc liên kết[- . '] == '.' ).

        trả lại (liên kết, None)

   # chuyển đổi liên kết tương đối thành liên kết tuyệt đối

    vô lý = liên kết url(url, link)

    # tải xuống nội dung của tệp

    dữ liệu = download_url(absurl)

    # lấy tên tệp

    tên tệp = tên cơ sở(absurl)

    # xây dựng đường dẫn đầu ra

    đường ngoài = tham gia(path, filename)

    # lưu vào tệp

    save_file(đường ra, data)

    # kết quả trả về

    return (link, outpath)

Phối hợp quá trình tải xuống

Cuối cùng, chúng ta cần điều phối quá trình tổng thể

Trước tiên, phải tải xuống URL của trang HTML bằng cách sử dụng download_url() function defined above.

1

2

3

.. .

# tải xuống trang web html

dữ liệu = download_url(url)

Tiếp theo, chúng ta cần tạo bất kỳ thư mục nào trên đường dẫn cục bộ mà chúng ta đã chọn để lưu trữ các tệp cục bộ. Chúng ta có thể làm điều này bằng cách sử dụng hàm makedirs() từ os module and ignore the case where the directories already exist.

1

2

3

.. .

# tạo thư mục cục bộ để lưu tệp

makedirs(đường dẫn, exist_ok=True)

Tiếp theo, chúng tôi sẽ truy xuất danh sách tất cả các liên kết tương đối đến các tệp được liệt kê trên trang HTML bằng cách gọi get_urls_from_html() function, and report how many links were found.

1

2

3

4

5

.. .

# phân tích cú pháp html và truy xuất tất cả các url href được liệt kê

liên kết = get_urls_from_html(dữ liệu)

# báo cáo tiến độ

in(f'Tìm thấy liên kết {len(links)} trong {url}'<)

Cuối cùng, chúng tôi sẽ duyệt qua danh sách các liên kết, tải từng liên kết xuống một tệp cục bộ bằng lệnh gọi tới download_url_to_file() function, then report the success or failure of the download.

1

2

3

4

5

6

7

8

9

10

.. .

# tải xuống từng tệp trên trang web

đối với liên kết trong liên kết.

    # tải url xuống tệp cục bộ

    liên kết, đường ra = download_url_to_file(url, link, path)

   # kiểm tra liên kết đã bị bỏ qua

    nếu đường ra Không:

        in(f'>đã bỏ qua {link})

    khác.

        in(f'Đã tải {link} xuống)

Liên kết cái này lại với nhau, hàm download_all_files() .

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

# tải xuống tất cả các tệp trên trang web được cung cấp theo đường dẫn được cung cấp

def download_all_files(url, path):

    # tải xuống trang web html

    dữ liệu = download_url(url)

    # tạo thư mục cục bộ để lưu tệp

    makedirs(đường dẫn, exist_ok=True)

    # phân tích cú pháp html và truy xuất tất cả href url được liệt kê

    liên kết = get_urls_from_html(data)

    # tiến trình báo cáo

    print(f'Đã tìm thấy {len(links)

    # tải xuống từng tệp trên trang web

    cho liên kết trong liên kết:

        # tải url xuống tệp cục bộ

        liên kết, đường ra = download_url_to_file(url, link, path)

        # kiểm tra liên kết đã bị bỏ qua

        nếu đường ra Không:

            in(f'>đã bỏ qua {link})

        khác.

            in(f'Đã tải {link} xuống)

Hoàn thành ví dụ

Bây giờ chúng tôi có tất cả các yếu tố để tải xuống tất cả các tệp được liệt kê trên trang web HTML

Hãy thử nghiệm nó

Chọn một trong các URL được liệt kê ở trên và sử dụng các chức năng mà chúng tôi đã phát triển để tải xuống tất cả các tệp được liệt kê

Trong trường hợp này, tôi sẽ chọn tải xuống tất cả các sửa đổi bot do bên thứ ba phát triển cho trò chơi máy tính Quake 1

1

2

3

.. .

# url của trang html liệt kê tất cả các tệp để tải xuống

URL = 'https. //www. cai nghiện. com/files/idgames2/quakec/bots/'

Dưới đây là một ví dụ về giao diện của trang web này

Python tải xuống tất cả các tệp từ url
Ảnh chụp màn hình của trang web HTML liệt kê tất cả Quake 1 Bots

Chúng tôi sẽ lưu tất cả các tệp trong thư mục cục bộ trong thư mục con tmp/ .

1

2

3

.. .

# thư mục cục bộ để lưu tất cả các tệp trên trang html

ĐƯỜNG = 'tmp'

Sau đó, chúng ta có thể gọi hàm download_all_files() .

1

2

3

.. .

# tải xuống tất cả các tệp trên trang web html

download_all_files(URL, PATH)

Liên kết điều này lại với nhau, ví dụ hoàn chỉnh về việc tải xuống tất cả các tệp trên trang web HTML được liệt kê bên dưới

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

#Trăn Siêu Nhanh. com

# tải xuống tuần tự tất cả các tệp từ một trang web

from os import makedirs

from os. đường dẫn nhập tên cơ sở

from os. path import join

từ urllib. yêu cầu nhập urlopen

từ urllib. phân tích cú pháp nhập urljoin

từ bs4 nhập BeautifulSoup

 

# tải tệp từ một URL, trả về nội dung của tệp đã tải xuống

def download_url(đường dẫn url):

    # mở kết nối với máy chủ

    với urlopen(đường dẫn url) as connection:

        # đọc nội dung của url dưới dạng byte và gửi lại

        trả lại kết nối. đọc()

 

# decode downloaded html and extract all links

def get_urls_from_html(nội dung):

    # giải mã nội dung được cung cấp dưới dạng văn bản ascii

    html = nội dung. giải mã('utf-8')

    # phân tích cú pháp tài liệu tốt nhất có thể

    súp = Súp đẹp(html, 'html.parser')

    # tìm tất cả

    tags = súp. find_all('a')

    # nhận tất cả các giá trị href (liên kết) hoặc Không có nếu không có (không chắc)

    return [t. lấy('href', None) for t in atags]

 

# lưu nội dung được cung cấp vào đường dẫn cục bộ

def save_file(đường dẫn, data):

    # mở tệp cục bộ để ghi

    với mở(đường dẫn, 'wb') as file:

        # ghi tất cả dữ liệu được cung cấp vào tệp

        tệp. ghi(dữ liệu)

 

# tải một tệp xuống thư mục cục bộ

def download_url_to_file(url, link, path):

    # bỏ qua url không hợp lệ hoặc tên tệp không hợp lệ

    nếu liên kết Không có or link == '../'.

        trả lại (liên kết, None)

    # kiểm tra xem không có phần mở rộng tệp nào

    nếu không (liên kết[-4] == '.' hoặc liên kết[- . '] == '.' ).

        trả lại (liên kết, None)

   # chuyển đổi liên kết tương đối thành liên kết tuyệt đối

    vô lý = liên kết url(url, link)

    # tải xuống nội dung của tệp

    dữ liệu = download_url(absurl)

    # lấy tên tệp

    tên tệp = tên cơ sở(absurl)

    # xây dựng đường dẫn đầu ra

    đường ngoài = tham gia(path, filename)

    # lưu vào tệp

    save_file(đường ra, data)

    # kết quả trả về

    return (link, outpath)

 

# tải xuống tất cả các tệp trên trang web được cung cấp theo đường dẫn được cung cấp

def download_all_files(url, path):

    # tải xuống trang web html

    dữ liệu = download_url(url)

    # tạo thư mục cục bộ để lưu tệp

    makedirs(đường dẫn, exist_ok=True)

    # phân tích cú pháp html và truy xuất tất cả href url được liệt kê

    liên kết = get_urls_from_html(data)

    # tiến trình báo cáo

    print(f'Đã tìm thấy {len(links)

    # tải xuống từng tệp trên trang web

    cho liên kết trong liên kết:

        # tải url xuống tệp cục bộ

        liên kết, đường ra = download_url_to_file(url, link, path)

        # kiểm tra liên kết đã bị bỏ qua

        nếu đường ra Không:

            in(f'>đã bỏ qua {link})

        khác.

            in(f'Đã tải {link} xuống)

 

# url của trang html liệt kê tất cả các tệp để tải xuống

URL = 'https. //www. cai nghiện. com/files/idgames2/quakec/bots/'

# thư mục cục bộ để lưu tất cả các tệp trên trang html

ĐƯỜNG = 'tmp'

# tải xuống tất cả các tệp trên trang web html

download_all_files(URL, PATH)

Việc chạy ví dụ trước tiên sẽ tải xuống trang web HTML liệt kê tất cả các tệp, sau đó tải xuống từng tệp được liệt kê trên trang vào thư mục tmp/ .

Quá trình này sẽ mất nhiều thời gian, có thể là 3-4 phút vì các tệp được tải xuống cùng một lúc

Khi chương trình chạy, nó sẽ báo cáo tiến độ hữu ích

Đầu tiên, nó nhận xét rằng 113 liên kết đã được tìm thấy trên trang và một số thư mục đã bị bỏ qua. Sau đó, nó báo cáo tên tệp và đường dẫn cục bộ của từng tệp được lưu

1

2

3

4

5

6

7

8

9

10

11

Đã tìm thấy 113 liên kết trong https. //www. cai nghiện. com/files/idgames2/quakec/bots/

> bỏ qua. /

>đã bỏ qua bộ khử/

>bỏ qua máy gặt/

kẻ tấn công đã tải xuống. txt sang tmp/kẻ tấn công. txt

kẻ tấn công đã tải xuống. zip vào tmp/kẻ tấn công. khóa kéo

Đã tải xuống bgadm101. txt to tmp/bgadm101. txt

Đã tải xuống bgadm101. nén vào tmp/bgadm101. khóa kéo

Downloaded bgbot16. txt sang tmp/bgbot16. txt

Downloaded bgbot16. nén vào tmp/bgbot16. zip

...

How long did it take to run on your computer?
Let me know in the comments below.

Tiếp theo, chúng ta sẽ xem xét lớp ThreadPoolExecutor có thể được sử dụng để tạo nhóm luồng công nhân cho phép chúng ta tăng tốc .

Chạy các vòng lặp của bạn bằng cách sử dụng tất cả các CPU, tải xuống cuốn sách MIỄN PHÍ của tôi để tìm hiểu cách thực hiện

Cách tạo một nhóm chủ đề công nhân với ThreadPoolExecutor

We can use the ThreadPoolExecutor class to speed up the download of multiple files listed on an HTML webpage.

Lớp ThreadPoolExecutor được cung cấp như một phần của đồng thời.tương lai để dễ dàng chạy các tác vụ đồng thời.

Các

ThreadPoolExecutor cung cấp nhóm chuỗi công nhân, khác với ProcessPoolExecutor cung cấp nhóm .

Nói chung là,

ThreadPoolExecutor nên được sử dụng cho các tác vụ liên kết với IO đồng thời, như tải xuống URL và ProcessPoolExecutor .

Using the

ThreadPoolExecutor được thiết kế để dễ dàng và đơn giản. Nó giống như “chế độ tự động” cho Python thread.
  1. Create the thread pool by calling ThreadPoolExecutor() .
  2. Submit tasks and get futures by calling submit() .
  3. Chờ và nhận kết quả khi nhiệm vụ hoàn thành bằng cách gọi as_completed().
  4. Tắt nhóm luồng bằng cách gọi shutdown()

Tạo nhóm chủ đề

First, a

ThreadPoolExecutor instance must be created.

Theo mặc định, nó sẽ tạo ra một nhóm luồng bằng với số lõi CPU hợp lý trong hệ thống của bạn cộng với bốn.

Điều này là tốt cho hầu hết các mục đích

1

2

3

.. .

# tạo nhóm luồng với số lượng luồng công nhân mặc định

pool = ThreadPoolExecutor()

Bạn có thể chạy hàng chục đến hàng trăm luồng liên kết IO đồng thời trên mỗi CPU, mặc dù có thể không phải hàng nghìn hoặc hàng chục nghìn

Bạn có thể chỉ định số lượng chuỗi sẽ tạo trong nhóm thông qua đối số max_workers ; .

1

2

3

.. .

# create a thread pool with 10 worker threads

pool = ThreadPoolExecutor(max_workers=10)

Gửi nhiệm vụ đến Thread Pool

Sau khi được tạo, chúng tôi có thể gửi các tác vụ vào nhóm để hoàn thành bằng cách sử dụng gửi() . function.

Hàm này lấy tên của hàm để gọi bất kỳ và tất cả các đối số và trả về một đối tượng Tương lai .

Các

Future là một lời hứa trả về kết quả từ nhiệm vụ (nếu có) và cung cấp cách xác định xem một nhiệm vụ cụ thể đã được hoàn thành hay chưa.

1

2

3

.. .

# gửi một nhiệm vụ

future = pool. gửi(my_task, arg1 . , arg2, .. . )

Có thể truy cập kết quả trả về từ một hàm do nhóm luồng thực thi thông qua kết quả() . Nó sẽ đợi cho đến khi có kết quả nếu cần hoặc trả về ngay nếu có kết quả. function on the future object. It will wait until the result is available, if needed, or return immediately if the result is available.

Ví dụ

1

2

3

.. .

# get the result from a future

result = future. kết quả()

Nhận kết quả khi hoàn thành nhiệm vụ

Cái hay của việc thực hiện các nhiệm vụ đồng thời là chúng ta có thể nhận được kết quả khi chúng có sẵn thay vì đợi các nhiệm vụ được hoàn thành theo thứ tự chúng đã được gửi

The đồng thời. futures module provides an as_completed() function that we can use to get results for tasks as they are completed, just like its name suggests.

Chúng ta có thể gọi hàm và cung cấp cho nó danh sách các đối tượng trong tương lai được tạo bằng cách gọi submit( . and it will return future objects as they are completed in whatever order.

For example, we can use a list comprehension to submit the tasks and create the list of future objects

1

2

3

.. .

# submit all tasks into the thread pool and create a list of futures

tương lai = [nhóm. gửi(my_func, nhiệm vụ) for task in tasks]

Then get results for tasks as they complete in a for loop

1

2

3

4

5

6

.. .

# lặp lại tất cả các nhiệm vụ đã gửi và nhận kết quả khi chúng có sẵn

for future in as_completed(futures).

# lấy kết quả

result = future. kết quả()

# làm điều gì đó với kết quả

Tắt nhóm chủ đề

Khi tất cả các tác vụ được hoàn thành, chúng tôi có thể đóng nhóm luồng, thao tác này sẽ giải phóng từng luồng và mọi tài nguyên mà nó có thể giữ (e. g. không gian ngăn xếp)

1

2

3

.. .

# shutdown the thread pool

nhóm. tắt máy()

An easier way to use the thread pool is via the context manager (the with keyword), which ensures it is closed automatically once we are finished with it.

1

2

3

4

5

6

7

8

9

10

.. .

# tạo nhóm chủ đề

với ThreadPoolExecutor(max_workers=10) as pool:

# gửi nhiệm vụ

tương lai = [nhóm. gửi(my_func, nhiệm vụ) for task in tasks]

# nhận kết quả khi chúng có sẵn

for future in as_completed(futures).

# lấy kết quả

result = future. kết quả()

# làm điều gì đó với kết quả

Bây giờ chúng ta đã quen thuộc với ThreadPoolExecutor và cách sử dụng nó, hãy xem cách chúng ta có thể điều chỉnh chương trình tải xuống URL của mình để tạo .

Bối rối với API lớp ThreadPoolExecutor?
Tải xuống bảng cheat PDF MIỄN PHÍ của tôi

Cách tải xuống nhiều tệp đồng thời

Chương trình tải URL xuống tệp có thể được điều chỉnh để sử dụng ThreadPoolExecutor với rất ít thay đổi.

Hàm download_all_files() hiện liệt kê danh sách . download_url_to_file() function for each.

Có thể cập nhật vòng lặp này thành submit() tasks to a

ThreadPoolExecutor , sau đó chúng ta có thể đợi các đối tượng trong tương lai thông qua lệnh gọi tới as_completed( . ) and report progress.

Ví dụ

1

2

3

4

5

6

7

8

9

10

11

12

13

14

.. .

# tạo nhóm chủ đề công nhân

với ThreadPoolExecutor(max_workers=20) as exe:

    # gửi tất cả tác vụ tải xuống tới chuỗi công nhân

    tương lai = [exe.gửi(download_url_to_file, url, link, path) for link in links]

    # báo cáo kết quả khi chúng có sẵn

    cho tương lai trong as_completed(futures):

        # truy xuất kết quả

        liên kết, đường ra = future.kết quả()

        # kiểm tra liên kết đã bị bỏ qua

        nếu đường ra Không:

            in(f'>đã bỏ qua {link})

        khác.

            in(f'Đã tải {link} xuống)

Ở đây, chúng tôi sử dụng 20 luồng cho tối đa 20 kết nối đồng thời đến máy chủ lưu trữ tệp. Điều này có thể cần được điều chỉnh tùy thuộc vào số lượng kết nối đồng thời được hỗ trợ bởi máy chủ mà bạn muốn tải tệp xuống từ đó

Phiên bản cập nhật của hàm download_all_files() . ThreadPoolExecutor is listed below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

# tải xuống tất cả các tệp trên trang web được cung cấp theo đường dẫn được cung cấp

def download_all_files(url, path):

    # tải xuống trang web html

    dữ liệu = download_url(url)

    # tạo thư mục cục bộ để lưu tệp

    makedirs(đường dẫn, exist_ok=True)

    # phân tích cú pháp html và truy xuất tất cả href url được liệt kê

    liên kết = get_urls_from_html(data)

    # tiến trình báo cáo

    print(f'Đã tìm thấy {len(links)

    # tạo nhóm chuỗi công nhân

    với ThreadPoolExecutor(max_workers=20) as exe:

        # gửi tất cả tác vụ tải xuống tới chuỗi công nhân

        hợp đồng tương lai = [exe.gửi(download_url_to_file, url, link, path) for link in links]

        # báo cáo kết quả khi chúng có sẵn

        cho tương lai trong as_completed(futures):

            # truy xuất kết quả

            liên kết, đường ra = future.kết quả()

            # kiểm tra liên kết đã bị bỏ qua

            nếu đường ra Không:

                        in(f'>đã bỏ qua {link})

            else.

                        in(f'Đã tải {link} xuống)

Liên kết điều này lại với nhau, ví dụ hoàn chỉnh về việc tải xuống đồng thời tất cả các bot quake 1 bằng cách sử dụng

ThreadPoolExecutor được liệt kê bên dưới.

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

#Trăn Siêu Nhanh. com

# tải xuống tuần tự tất cả các tệp từ một trang web

from os import makedirs

from os. đường dẫn nhập tên cơ sở

from os. path import join

từ urllib. yêu cầu nhập urlopen

từ urllib. phân tích cú pháp nhập urljoin

từ đồng thời. tương lai nhập ThreadPoolExecutor

từ đồng thời. tương lai nhập as_completed

từ bs4 nhập BeautifulSoup

 

# tải tệp từ một URL, trả về nội dung của tệp đã tải xuống

def download_url(đường dẫn url):

    # mở kết nối với máy chủ

    với urlopen(đường dẫn url) as connection:

        # đọc nội dung của url dưới dạng byte và gửi lại

        trả lại kết nối. đọc()

 

# decode downloaded html and extract all links

def get_urls_from_html(nội dung):

    # giải mã nội dung được cung cấp dưới dạng văn bản ascii

    html = nội dung. giải mã('utf-8')

    # phân tích cú pháp tài liệu tốt nhất có thể

    súp = Súp đẹp(html, 'html.parser')

    # tìm tất cả

    tags = súp. find_all('a')

    # nhận tất cả các giá trị href (liên kết) hoặc Không có nếu không có (không chắc)

    return [t. lấy('href', None) for t in atags]

 

# lưu nội dung được cung cấp vào đường dẫn cục bộ

def save_file(đường dẫn, data):

    # mở tệp cục bộ để ghi

    với mở(đường dẫn, 'wb') as file:

        # ghi tất cả dữ liệu được cung cấp vào tệp

        tệp. ghi(dữ liệu)

 

# tải một tệp xuống thư mục cục bộ

def download_url_to_file(url, link, path):

    # bỏ qua url không hợp lệ hoặc tên tệp không hợp lệ

    nếu liên kết Không có or link == '../'.

        trả lại (liên kết, None)

    # kiểm tra xem không có phần mở rộng tệp nào

    nếu không (liên kết[-4] == '.' hoặc liên kết[- . '] == '.' ).

        trả lại (liên kết, None)

   # chuyển đổi liên kết tương đối thành liên kết tuyệt đối

    vô lý = liên kết url(url, link)

    # tải xuống nội dung của tệp

    dữ liệu = download_url(absurl)

    # lấy tên tệp

    tên tệp = tên cơ sở(absurl)

    # xây dựng đường dẫn đầu ra

    đường ngoài = tham gia(path, filename)

    # lưu vào tệp

    save_file(đường ra, data)

    # kết quả trả về

    return (link, outpath)

 

# tải xuống tất cả các tệp trên trang web được cung cấp theo đường dẫn được cung cấp

def download_all_files(url, path):

    # tải xuống trang web html

    dữ liệu = download_url(url)

    # tạo thư mục cục bộ để lưu tệp

    makedirs(đường dẫn, exist_ok=True)

    # phân tích cú pháp html và truy xuất tất cả href url được liệt kê

    liên kết = get_urls_from_html(data)

    # tiến trình báo cáo

    print(f'Đã tìm thấy {len(links)

    # tạo nhóm chuỗi công nhân

    với ThreadPoolExecutor(max_workers=20) as exe:

        # gửi tất cả tác vụ tải xuống tới chuỗi công nhân

        hợp đồng tương lai = [exe.gửi(download_url_to_file, url, link, path) for link in links]

        # báo cáo kết quả khi chúng có sẵn

        cho tương lai trong as_completed(futures):

            # truy xuất kết quả

            liên kết, đường ra = future.kết quả()

            # kiểm tra liên kết đã bị bỏ qua

            nếu đường ra Không:

                        in(f'>đã bỏ qua {link})

            else.

                        in(f'Đã tải {link} xuống)

 

# url của trang html liệt kê tất cả các tệp để tải xuống

URL = 'https. //www. cai nghiện. com/files/idgames2/quakec/bots/'

# thư mục cục bộ để lưu tất cả các tệp trên trang html

ĐƯỜNG = 'tmp'

# tải xuống tất cả các tệp trên trang web html

download_all_files(URL, PATH)

Chạy ví dụ trước tiên sẽ tải xuống và phân tích cú pháp trang HTML liệt kê tất cả các tệp cục bộ

Mỗi tệp trên trang sau đó được tải xuống đồng thời, với tối đa 20 tệp được tải xuống cùng một lúc

Điều này tăng tốc đáng kể tác vụ, mất 10-15 giây tùy thuộc vào kết nối internet của bạn, so với 3-4 phút cho phiên bản tuần tự. Đó là về tốc độ tăng tốc 33 lần

Tiến trình được báo cáo như lần trước, nhưng chúng ta có thể thấy rằng các tệp được báo cáo không theo thứ tự

Ở đây, chúng ta có thể thấy rằng càng nhỏ. txt kết thúc trước bất kỳ. tập tin zip

1

2

3

4

5

6

7

8

9

10

11

Đã tìm thấy 113 liên kết trong https. //www. cai nghiện. com/files/idgames2/quakec/bots/

> bỏ qua. /

>đã bỏ qua bộ khử/

>bỏ qua máy gặt/

Đã tải xuống bgadm101. txt to tmp/bgadm101. txt

kẻ tấn công đã tải xuống. txt sang tmp/kẻ tấn công. txt

Downloaded bgbot16. txt sang tmp/bgbot16. txt

Đã tải xuống bgbot20a. txt sang tmp/bgbot20a. txt

Đã tải xuống borg12. txt sang tmp/borg12. txt

Đã tải xuống bplayer2. txt sang tmp/bplayer2. txt

...

How long did it take to run on your computer?
Let me know in the comments below.


Khóa học Python ThreadPoolExecutor miễn phí

Tải xuống bảng gian lận API ThreadPoolExecutor của tôi và như một phần thưởng, bạn sẽ có quyền truy cập MIỄN PHÍ vào khóa học email 7 ngày của tôi

Khám phá cách sử dụng lớp ThreadPoolExecutor bao gồm cách định cấu hình số lượng công nhân và cách thực thi tác vụ không đồng bộ

Tìm hiểu thêm
 


Tiện ích mở rộng

Phần này liệt kê các ý tưởng để mở rộng hướng dẫn

Share your extensions in the comments below; it would be great to see what you come up with

Choáng ngợp trước các API đồng thời của python?
Để tìm sự giải thoát, hãy tải xuống Bản đồ tư duy về đồng thời Python MIỄN PHÍ của tôi

Đọc thêm

Phần này cung cấp các tài nguyên bổ sung mà bạn có thể thấy hữu ích

Sách

I also recommend specific chapters from the following books

hướng dẫn

API

mang đi

Trong hướng dẫn này, bạn đã học cách tải xuống đồng thời nhiều tệp bằng cách sử dụng nhóm chuỗi công nhân trong Python. Bạn đã học

Làm cách nào để tải xuống tất cả các tệp từ URL Python?

Để tải xuống tệp từ một URL bằng Python, hãy làm theo ba bước sau. .
Cài đặt mô-đun yêu cầu và nhập nó vào dự án của bạn
sử dụng yêu cầu. get() để tải xuống dữ liệu đằng sau URL đó
Ghi tệp vào một tệp trong hệ thống của bạn bằng cách gọi open()

Làm cách nào để tải xuống dữ liệu từ URL trong Python?

Khoa học dữ liệu thực tế sử dụng Python .
Nhập mô-đun. yêu cầu nhập khẩu
Nhận liên kết hoặc url. url = 'https. //www. Facebook. com/favicon. ico' r = yêu cầu. get(url, allow_redirects=True)
Lưu nội dung với tên. mở Facebook. ico', 'wb'). nhà văn. nội dung) lưu tệp dưới dạng facebook. ico

Tôi có thể sử dụng Python để tải xuống tệp từ trang web không?

Requests là một thư viện HTTP linh hoạt trong python với nhiều ứng dụng khác nhau. Một trong những ứng dụng của nó là tải xuống tệp từ trang web bằng URL của tệp . Hoặc tải trực tiếp từ đây và cài đặt thủ công.

Làm cách nào để đọc tệp từ URL trong Python?

5 cách để đọc tệp văn bản từ một URL .
Phương pháp 1. sử dụng urllib. yêu cầu. urlopen()
Phương pháp 2. sử dụng yêu cầu. được()
Phương pháp 3. Sử dụng urllib3. Trình quản lý hồ bơi ()
Phương pháp 4. sử dụng urllib. yêu cầu. urlopen(). đọc (n)
Phương pháp 5. sử dụng urllib. yêu cầu. urlopen(). đọc()