【问题标题】:Download all pdf files from a website using Python使用 Python 从网站下载所有 pdf 文件
【发布时间】:2019-07-04 03:01:02
【问题描述】:

我遵循了几个在线指南,试图构建一个脚本,该脚本可以识别和下载网站上的所有 pdf,从而使我免于手动操作。到目前为止,这是我的代码:

from urllib import request
from bs4 import BeautifulSoup
import re
import os
import urllib

# connect to website and get list of all pdfs
url="http://www.gatsby.ucl.ac.uk/teaching/courses/ml1-2016.html"
response = request.urlopen(url).read()
soup= BeautifulSoup(response, "html.parser")     
links = soup.find_all('a', href=re.compile(r'(.pdf)'))


# clean the pdf link names
url_list = []
for el in links:
    url_list.append(("http://www.gatsby.ucl.ac.uk/teaching/courses/" + el['href']))
#print(url_list)


# download the pdfs to a specified location
for url in url_list:
    print(url)
    fullfilename = os.path.join('E:\webscraping', url.replace("http://www.gatsby.ucl.ac.uk/teaching/courses/ml1-2016/", "").replace(".pdf",""))
    print(fullfilename)
    request.urlretrieve(url, fullfilename)

该代码似乎可以找到所有 pdf(取消注释 print(url_list) 以查看此内容)。但是,它在下载阶段失败。特别是我得到了这个错误,我无法理解出了什么问题:

E:\webscraping>python get_pdfs.py
http://www.gatsby.ucl.ac.uk/teaching/courses/http://www.gatsby.ucl.ac.uk/teaching/courses/ml1-2016/cribsheet.pdf
E:\webscraping\http://www.gatsby.ucl.ac.uk/teaching/courses/cribsheet
Traceback (most recent call last):
  File "get_pdfs.py", line 26, in <module>
    request.urlretrieve(url, fullfilename)
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 248, in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 223, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 532, in open
    response = meth(req, response)
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 642, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 570, in error
    return self._call_chain(*args)
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 504, in _call_chain
    result = func(*args)
  File "C:\Users\User\Anaconda3\envs\snake\lib\urllib\request.py", line 650, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 404: Not Found

有人可以帮帮我吗?

【问题讨论】:

    标签: python regex url web-scraping beautifulsoup


    【解决方案1】:

    查看以下实现。我使用requests 模块而不是urllib 进行下载。此外,我使用.select() 方法而不是.find_all() 来避免使用re

    import os
    import requests
    from urllib.parse import urljoin
    from bs4 import BeautifulSoup
    
    url = "http://www.gatsby.ucl.ac.uk/teaching/courses/ml1-2016.html"
    
    #If there is no such folder, the script will create one automatically
    folder_location = r'E:\webscraping'
    if not os.path.exists(folder_location):os.mkdir(folder_location)
    
    response = requests.get(url)
    soup= BeautifulSoup(response.text, "html.parser")     
    for link in soup.select("a[href$='.pdf']"):
        #Name the pdf files using the last portion of each link which are unique in this case
        filename = os.path.join(folder_location,link['href'].split('/')[-1])
        with open(filename, 'wb') as f:
            f.write(requests.get(urljoin(url,link['href'])).content)
    

    【讨论】:

    • 谢谢。这是简短而干净的。这是我第一次使用网络爬虫——它通常很慢吗?每个文件需要几秒钟?谢谢。
    • @SIM,如何以亚洲字符(URL 的一部分)命名下载的 PDF?我看到了这一点,但不确定如何将其放入上述代码中:qiita.com/mix/items/87d094414e46f857de45
    • @SIM 这适用于提供的链接。我正在另一个页面上尝试,我知道有几个指向 pdf 文档的链接。我只得到 2 个。
    • 嗨,我知道有点晚了,请,我尝试了这个 URL = "covidmaroc.ma/Pages/LESINFOAR.aspx" 上的代码,但它没有工作,我不知道为什么,因为我不熟悉网络抓取,请提供任何帮助。
    【解决方案2】:

    一般来说,上面的答案应该有效。但是,您应该评估您尝试使用的网页的 html 源代码。例如,有些可能在元标记中有 og_url 属性,而有些可能没有。如果您使用的是安全网站(假设您的大学的课程网页),这是可能的。在这种情况下,您必须以不同的方式提取 pdf 链接。

    你可以在这里找到一个很好的解释和解决方案:

    https://medium.com/@dementorwriter/notesdownloader-use-web-scraping-to-download-all-pdfs-with-python-511ea9f55e48

    【讨论】:

      【解决方案3】:

      几个链接已经包含导致 404 未找到的服务器地址。此外,您不应从文件名中删除 .pdf,因为它会在没有扩展名的情况下保存它。

      from urllib import request
      from bs4 import BeautifulSoup
      import re
      import os
      import urllib
      
      # connect to website and get list of all pdfs
      url="http://www.gatsby.ucl.ac.uk/teaching/courses/ml1-2016.html"
      response = request.urlopen(url).read()
      soup= BeautifulSoup(response, "html.parser")     
      links = soup.find_all('a', href=re.compile(r'(.pdf)'))
      
      
      # clean the pdf link names
      url_list = []
      for el in links:
      if(el['href'].startswith('http')):
          url_list.append(el['href'])
      else:
          url_list.append("http://www.gatsby.ucl.ac.uk/teaching/courses/" + el['href'])
      
      print(url_list)
      
      
      # download the pdfs to a specified location
      for url in url_list:
          print(url)
          fullfilename = os.path.join('E:\webscraping', url.replace("http://www.gatsby.ucl.ac.uk/teaching/courses/ml1-2016/", ""))
          print(fullfilename)
          request.urlretrieve(url, fullfilename)
      

      【讨论】:

      • 这是一个很好的答案。它工作得很好。谢谢。
      • 如果我们提供基本 url,此方法是从网页还是整个网站域下载所有 pdf 文件?
      【解决方案4】:

      我根据@SIM's answer 和附加的argparse 编写了一个新颖的脚本。我的完整代码如下:

      import os
      import requests
      from urllib.parse import urljoin
      from bs4 import BeautifulSoup
      import argparse
      
      #%% Example
      # one pdf
      #   python all_pdf_dl.py -l https://memento.epfl.ch/academic-calendar/ --save-here
      # many pdfs
      #   python all_pdf_dl.py -l https://idsc.ethz.ch/education/lectures/recursive-estimation.html
      
      #%% Functions
      def all_pdf_download(args):
          base_url = args.link
          if args.save_here:
              folder_path = os.getcwd()
          else:
              folder_path = args.folder_path
              if not os.path.exists(args.folder_path):os.mkdir(args.folder_path)
          print("====== 1. Set savepath: {} ======".format(folder_path))
          print("====== 2. Start searching ======")
          #response = requests.get(base_url)
          response = requests.get(base_url, headers={'User-Agent': 'Custom'})
          soup= BeautifulSoup(response.text, "html.parser")
          search_res = soup.select("a[href$='.pdf']")
          print("{} files found!!!".format(len(search_res)))
          print("====== 3. Start downloading ======")
          for counter, link in enumerate(search_res):
              #Name the pdf files using the last portion of each link which are unique in this case
              filename = link['href'].split('/')[-1]
              file_save_path = os.path.join(folder_path,link['href'].split('/')[-1])
              if args.print_all:
                  print("[{}/{}] {}".format(counter+1, len(search_res), filename))
              with open(file_save_path, 'wb') as f:
                  f.write(requests.get(urljoin(base_url,link['href'])).content)
          print("====== 4. Finished!!! ======")
      
      if __name__ == "__main__":
          parser = argparse.ArgumentParser(description='Test argparse')
          ####################################
          ############ ALL OPTION ############
          ## Main option
          # -l/--link
          parser.add_argument('-l', '--link', required=True, type=str,
                              help='write down site name')
          # --print-all
          parser.add_argument('--print-all', dest='print_all', action='store_true',
                              help="print all filename")
          parser.set_defaults(print_all=True)
          # --save-here
          parser.add_argument('--save-here', dest='save_here', action='store_true',
                              help="save files here")
          parser.set_defaults(save_here=False)
          # --save--folder
          # default setting -> Downloads/ in user’s home directory obtained by (os.path.expanduser('~'))
          parser.add_argument('-f', '--folder_path', default=r""+os.path.join(os.path.expanduser('~'), "Downloads"), 
                              type=str, help='save files in the given folder')
      
          ########################################
          ############ PARSING OPTION ############
          args = parser.parse_args()
          all_pdf_download(args)
      

      更多详情和更新可以参考我的gist-hibetterheyj/all_pdf_dl.py

      最好的!

      【讨论】:

      • 如果我们提供基本 url,此方法是从网页还是整个网站域下载所有 pdf 文件?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-10
      • 2014-03-14
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2016-08-25
      相关资源
      最近更新 更多