使用Python+Requests从alldatasheet下载指定文件

最近需要从全球电子元器件数据手册库 网上下载一些datasheet文件,手动下载比较耗时,写个下载脚本可以节省很多时间,且可以在需要下载内容更新后重复使用,提高效率。

涉及到的知识点

  1. Python读写Excel
  2. Python requests 模块

Excel管理表格

需求

  1. 根据“分类”创建文件夹,即不同分类对应的下载后的pdf文件放在不同文件夹中。
  2. 根据“型号规格”命名文件,即下载后,把文件名命名为“型号规格.pdf”,如”ADG201AKR.pdf”。
  3. 根据“是否已经下载”来判断该行内容是否需要下载。如果为“Yes”,则表明已经下载过;如果为“No”则需要下载,同时下载后需要把标记改为“Yes”。
  4. 根据“链接”下载该行对应的pdf文件。即不需要搜索,直接用此链接下载。
  5. “分类”“型号规格”“是否已经下载”“链接”在Excel中的列位置固定,下载程序中按位置查找(可以升级为按名称查找)

观察下载过程,查找真实下载链接

  1. 在网页中打开给定的下载链接,如:https://www.alldatasheet.com/datasheet-pdf/pdf/79516/INFINEON/BTS6163D.html
  2. 点击“Download”后,发现下载链接会变化为:https://pdf1.alldatasheet.com/datasheet-pdf/download/79516/INFINEON/BTS6163D.html。
    该链接为真正的下载链接。

获取下载方式及参数

  1. 打开网址 https://www.alldatasheet.com/
  2. 搜索关键字,如 BTS6163D。也可以直接打开Excel中给定的下载链接
  3. 选择查看方式中的Download。结果如下图:
    alldatasheet_download_webpage
  4. 在下面的”Download”按钮上右键,并选择弹出菜单中的”查看元素”(如果是Chrome浏览器,则对应选项”检查”),可以查看到该按钮的响应为一个==Post==请求。注意,该post请求有一个参数:
<input name="tmpinfo1aa" type="hidden" value="abc">

alldatasheet_download_webpage_find_submit

代码

代码如下:

import openpyxl
import requests
import time
import os

class ExcelOp(object):
    def __init__(self, file):
        self.file = file
        self.wb = openpyxl.load_workbook(self.file)
        sheets = self.wb.sheetnames
        self.sheet = sheets[0]
        self.ws = self.wb[self.sheet]

    # 获取表格的总行数和总列数
    def get_row_clo_num(self):
        rows = self.ws.max_row
        columns = self.ws.max_column
        return rows, columns

    # 获取某个单元格的值
    def get_cell_value(self, row, column):
        cell_value = self.ws.cell(row=row, column=column).value
        return cell_value

    # 获取某列的所有值
    def get_col_value(self, column):
        rows = self.ws.max_row
        column_data = []
        for i in range(1, rows + 1):
            cell_value = self.ws.cell(row=i, column=column).value
            column_data.append(cell_value)
        return column_data

    # 获取某行所有值
    def get_row_value(self, row):
        columns = self.ws.max_column
        row_data = []
        for i in range(1, columns + 1):
            cell_value = self.ws.cell(row=row, column=i).value
            row_data.append(cell_value)
        return row_data

    # 设置某个单元格的值
    def set_cell_value(self, row, colunm, cellvalue):
        try:
            self.ws.cell(row=row, column=colunm).value = cellvalue
            self.wb.save(self.file)
        except:
            self.ws.cell(row=row, column=colunm).value = "writefail"
            self.wb.save(self.file)

class Downloader(object):

    def download_from_alldatasheet(self, filename, url, savefolder=""):
        SUCCESS = False
        filename = filename + ".pdf"

        params = {
            "tmpinfo1aa": "abc",
        }
        while not SUCCESS:
            print("尝试URL连接中...")
            req = requests.request(method='POST', url=url, params=params)
            print("获取返回内容信息文本,如果是pdf,比较耗时,请等待...")
            text = req.text
            print("获取返回内容信息文本完成。")
            if text.find("Download is temporarily unavailable") != -1:
                print("下载太频繁,等待五分钟......,等待中")
                time.sleep(300)
                continue
            else:
                SUCCESS = True
            # print(filename + " : \n")
            # print(text)
            data = req.content
            full_savefolder = os.path.join(os.path.abspath(os.curdir), savefolder)
            if not os.path.exists(full_savefolder):
                os.mkdir(full_savefolder)
            full_filepath = os.path.join(full_savefolder, filename)
            print("尝试存储文件:" + filename)
            with open(full_filepath, "wb") as code:
                code.write(data)
                print("存储文件:" + filename + "完成")
                return True
        return False

    def valid_url(self, url):
        # https://www.alldatasheet.com/datasheet-pdf/pdf/436213/HITTITE/HMC704LP4E.html
        if str(url).startswith("https://www.alldatasheet.com/datasheet-pdf/pdf/"):
            return True
        return False

    def is_tbd(self, checkstr):
        if str(checkstr).strip().lower() == 'no':
            return True
        return False

    def transfer_url(self, url):
        # https://www.alldatasheet.com/datasheet-pdf/pdf/436213/HITTITE/HMC704LP4E.html
        before = "https://www.alldatasheet.com/datasheet-pdf/pdf/"
        after = "https://pdf1.alldatasheet.com/datasheet-pdf/download/"
        return str(url).replace(before, after)

if __name__ == "__main__":
    excel_op = ExcelOp(file="LIST.xlsx")
    downloader = Downloader()
    # 1-'', 4-型号规格, 6-下载, 7-链接
    need_cols = [1,4,6,7]
    rows, columns = excel_op.get_row_clo_num()
    # 从第二行开始解析下载
    for i in range(2,rows+1):
        need_col_values = []
        for j in need_cols:
            cell_val = excel_op.get_cell_value(i,j)
            need_col_values.append(cell_val)

        print(need_col_values)

        savefolder = need_col_values[0]
        filename = need_col_values[1]
        str_TBD = need_col_values[2]
        url = need_col_values[3]

        if downloader.is_tbd(str_TBD) and downloader.valid_url(url):
            url = downloader.transfer_url(url)
            res = downloader.download_from_alldatasheet(filename, url, savefolder)
            if res:
                excel_op.set_cell_value(i, 6, 'Yes')

运行过程

在命令行运行结果示例:

C:\Users\Administrator\Download>python download.py
['A', 'ADG201AKR', 'No', 'https://www.alldatasheet.com/datasheet-pdf/pdf/48648/AD/ADG201AKR.html']
尝试URL连接中...
获取返回内容信息文本,如果是pdf,比较耗时,请等待...
获取返回内容信息文本完成。
尝试存储文件:ADG201AKR.pdf
存储文件:ADG201AKR.pdf完成
......
['C', 'TPS5450DDA', 'No', 'https://www.alldatasheet.com/datasheet-pdf/pdf/180875/TI/TPS5450DDA.html']
尝试URL连接中...
获取返回内容信息文本,如果是pdf,比较耗时,请等待...
获取返回内容信息文本完成。
下载太频繁,等待五分钟......,等待中
尝试URL连接中...
获取返回内容信息文本,如果是pdf,比较耗时,请等待...
获取返回内容信息文本完成。
尝试存储文件:TPS5450DDA.pdf
存储文件:TPS5450DDA.pdf完成
['C', 'DCP010512BP', 'No', 'https://www.alldatasheet.com/datasheet-pdf/pdf/527520/TI1/DCP010512BP-U.html']
尝试URL连接中...
获取返回内容信息文本,如果是pdf,比较耗时,请等待...
获取返回内容信息文本完成。
尝试存储文件:DCP010512BP.pdf
存储文件:DCP010512BP.pdf完成

说明

连续下载10个pdf后,网站会提示输入验证码,网页中含有信息“Download is temporarily unavailable”。观察发现,在遇到提示后,等待几分钟,便可以继续下载。程序中:在遇到下载失败后,会等待了5分钟,然后继续下载。

Fork/Star on Github