32

Mechanizeを含むファイルをダウンロードしていますが、応答ヘッダーに次の文字列があります。

Content-Disposition: attachment; filename=myfilename.txt

そのファイル名の値を取得するための簡単な標準的な方法はありますか?私が今心に留めているのはこれです:

filename = f[1]['Content-Disposition'].split('; ')[1].replace('filename=', '')

しかし、それは手っ取り早い「汚い」解決策のように見えます。

4

3 に答える 3

6

これらの正規表現は、RFC 6266 の文法に基づいていますが、disposition-type のないヘッダーを受け入れるように変更されています (例: Content-Disposition: filename=example.html)。

すなわち[気質タイプ「;」] 気質-parm ( ";" 気質-parm )* / 気質タイプ

引用符の有無にかかわらずファイル名パラメーターを処理し、引用符で囲まれた値から引用符で囲まれたペアをアンクォートします。例: filename="foo\"bar" -> foo"bar

ファイル名 * 拡張パラメーターを処理し、ヘッダーに表示される順序に関係なく、ファイル名パラメーターよりもファイル名 * 拡張パラメーターを優先します。

/etc/passwd -> passwd などのフォルダー名情報を削除し、ファイル名パラメーター (またはヘッダー、またはパラメーター値が空の文字列の場合) がない場合は、URL パスからベース名にデフォルト設定されます。

token と qdtext の正規表現は RFC 2616 の文法に基づいており、mimeCharset と valueChars の正規表現は RFC 5987 の文法に基づいており、言語の正規表現は RFC 5646 の文法に基づいています。

import re, urllib
from os import path
from urlparse import urlparse

# content-disposition = "Content-Disposition" ":"
#                        disposition-type *( ";" disposition-parm )
# disposition-type    = "inline" | "attachment" | disp-ext-type
#                     ; case-insensitive
# disp-ext-type       = token
# disposition-parm    = filename-parm | disp-ext-parm
# filename-parm       = "filename" "=" value
#                     | "filename*" "=" ext-value
# disp-ext-parm       = token "=" value
#                     | ext-token "=" ext-value
# ext-token           = <the characters in token, followed by "*">

token = '[-!#-\'*+.\dA-Z^-z|~]+'
qdtext='[]-~\t !#-[]'
mimeCharset='[-!#-&+\dA-Z^-z]+'
language='(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}(?:-[A-Za-z]{3}){,2})?|[A-Za-z]{4,8})(?:-[A-Za-z]{4})?(?:-(?:[A-Za-z]{2}|\d{3}))(?:-(?:[\dA-Za-z]{5,8}|\d[\dA-Za-z]{3}))*(?:-[\dA-WY-Za-wy-z](?:-[\dA-Za-z]{2,8})+)*(?:-[Xx](?:-[\dA-Za-z]{1,8})+)?|[Xx](?:-[\dA-Za-z]{1,8})+|[Ee][Nn]-[Gg][Bb]-[Oo][Ee][Dd]|[Ii]-[Aa][Mm][Ii]|[Ii]-[Bb][Nn][Nn]|[Ii]-[Dd][Ee][Ff][Aa][Uu][Ll][Tt]|[Ii]-[Ee][Nn][Oo][Cc][Hh][Ii][Aa][Nn]|[Ii]-[Hh][Aa][Kk]|[Ii]-[Kk][Ll][Ii][Nn][Gg][Oo][Nn]|[Ii]-[Ll][Uu][Xx]|[Ii]-[Mm][Ii][Nn][Gg][Oo]|[Ii]-[Nn][Aa][Vv][Aa][Jj][Oo]|[Ii]-[Pp][Ww][Nn]|[Ii]-[Tt][Aa][Oo]|[Ii]-[Tt][Aa][Yy]|[Ii]-[Tt][Ss][Uu]|[Ss][Gg][Nn]-[Bb][Ee]-[Ff][Rr]|[Ss][Gg][Nn]-[Bb][Ee]-[Nn][Ll]|[Ss][Gg][Nn]-[Cc][Hh]-[Dd][Ee]'
valueChars = '(?:%[\dA-F][\dA-F]|[-!#$&+.\dA-Z^-z|~])*'
dispositionParm = '[Ff][Ii][Ll][Ee][Nn][Aa][Mm][Ee]\s*=\s*(?:({token})|"((?:{qdtext}|\\\\[\t !-~])*)")|[Ff][Ii][Ll][Ee][Nn][Aa][Mm][Ee]\*\s*=\s*({mimeCharset})\'(?:{language})?\'({valueChars})|{token}\s*=\s*(?:{token}|"(?:{qdtext}|\\\\[\t !-~])*")|{token}\*\s*=\s*{mimeCharset}\'(?:{language})?\'{valueChars}'.format(**locals())

try:
  m = re.match('(?:{token}\s*;\s*)?(?:{dispositionParm})(?:\s*;\s*(?:{dispositionParm}))*|{token}'.format(**locals()), result.headers['Content-Disposition'])

except KeyError:
  name = path.basename(urllib.unquote(urlparse(url).path))

else:
  if not m:
    name = path.basename(urllib.unquote(urlparse(url).path))

  # Many user agent implementations predating this specification do not
  # understand the "filename*" parameter.  Therefore, when both "filename"
  # and "filename*" are present in a single header field value, recipients
  # SHOULD pick "filename*" and ignore "filename"

  elif m.group(8) is not None:
    name = urllib.unquote(m.group(8)).decode(m.group(7))

  elif m.group(4) is not None:
    name = urllib.unquote(m.group(4)).decode(m.group(3))

  elif m.group(6) is not None:
    name = re.sub('\\\\(.)', '\1', m.group(6))

  elif m.group(5) is not None:
    name = m.group(5)

  elif m.group(2) is not None:
    name = re.sub('\\\\(.)', '\1', m.group(2))

  else:
    name = m.group(1)

  # Recipients MUST NOT be able to write into any location other than one to
  # which they are specifically entitled

  if name:
    name = path.basename(name)

  else:
    name = path.basename(urllib.unquote(urlparse(url).path))
于 2012-08-18T09:47:05.203 に答える
-1

私は次のようなことを試します:

import re
filename = re.findall("filename=(\S+)", f[1]['Content-Disposition'])

これにより、ファイル名の引用符と URL エスケープが処理されます。

于 2011-11-07T18:18:17.347 に答える