จะค้นหาไฟล์ประเภท mime ในไพ ธ อนได้อย่างไร?


194

สมมติว่าคุณต้องการบันทึกไฟล์ไว้ที่ใดที่หนึ่งตัวอย่างเช่นใน BLOBs สมมติว่าคุณต้องการลบไฟล์เหล่านี้ออกทางหน้าเว็บและให้ลูกค้าเปิดแอปพลิเคชั่น / โปรแกรมดูที่ถูกต้องโดยอัตโนมัติ

ข้อสันนิษฐาน: เบราว์เซอร์จะพิจารณาว่าแอปพลิเคชัน / โปรแกรมดูใดที่จะใช้โดยส่วนหัว mime-type (content-type?) ในการตอบกลับ HTTP

ขึ้นอยู่กับสมมติฐานนั้นนอกเหนือจากไบต์ของไฟล์คุณยังต้องการบันทึกประเภท MIME

คุณจะค้นหาไฟล์ประเภท MIME ได้อย่างไร? ฉันใช้ Mac อยู่ในขณะนี้ แต่สิ่งนี้ก็ควรจะใช้ได้บน Windows

เบราว์เซอร์เพิ่มข้อมูลนี้เมื่อโพสต์ไฟล์ไปยังหน้าเว็บหรือไม่?

มีห้องสมุดไพ ธ อนที่เรียบร้อยสำหรับการค้นหาข้อมูลนี้หรือไม่? WebService หรือ (ดียิ่งขึ้น) ฐานข้อมูลที่สามารถดาวน์โหลดได้?

คำตอบ:


218

วิธีการของ python-magic ที่แนะนำโดย toivotuo นั้นล้าสมัยแล้ว ลำตัวปัจจุบันของ Python-magicอยู่ที่ Github และจาก readme ที่นั่นเพื่อค้นหา MIME-type จะทำเช่นนี้

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'

17
ขอบคุณสำหรับความคิดเห็น! โปรดทราบว่า "ด้านบน" เป็นแนวคิดที่ยากใน stackoverflow เนื่องจากลำดับจะถูกจัดกลุ่มตามคะแนนโหวตและสั่งซื้อแบบสุ่มภายในกลุ่ม ฉันเดาว่าคุณหมายถึงคำตอบของ @ toivotuo
Daren Thomas

1
ใช่ฉันไม่มี "คะแนน" เพียงพอในการสร้างความคิดเห็นในขณะที่เขียนคำตอบนี้ แต่ฉันน่าจะเขียนเป็นความคิดเห็นเพื่อที่ @toivotuo สามารถแก้ไขคำถามของเขาได้
Simon Zimmermann

1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file บทสรุป: Python รวมสำหรับ libmagic API rpm -qf / usr / bin / file -i ชื่อ: ไฟล์ URL: darwinsys.com/file python-magic จากdarwinsys.com/fileซึ่งมาพร้อมกับ Linux Fedora ทำงานเหมือน @ toivotuo และดูเหมือนกระแสหลักมากขึ้น
Sérgio

7
ระวังว่าแพ็คเกจ debian / ubuntu ที่เรียกว่า python-magic ต่างจากแพ็คเกจ pip ที่ชื่อเดียวกัน ทั้งคู่มีimport magicแต่เนื้อหาที่เข้ากันไม่ได้ ดูstackoverflow.com/a/16203777/3189เพิ่มเติม
Hamish Downer

1
ในขณะที่ฉันแสดงความคิดเห็นต่อคำตอบของ toivotuo มันไม่ล้าสมัย! คุณกำลังพูดถึงห้องสมุดอื่น คุณกรุณาลบหรือแทนที่คำแถลงนั้นในคำตอบของคุณได้ไหม ปัจจุบันทำให้การค้นหาทางออกที่ดีที่สุดเป็นเรื่องยากจริงๆ
bodo

87

ชนิด mime โมดูลในห้องสมุดมาตรฐานจะกำหนด / เดาชนิดไมม์จากนามสกุลไฟล์

หากผู้ใช้กำลังอัปโหลดไฟล์โพสต์ HTTP จะมีประเภท MIME ของไฟล์ข้างข้อมูล ตัวอย่างเช่น Django ทำให้ข้อมูลนี้พร้อมใช้งานเป็นแอตทริบิวต์ของวัตถุUploadFile


12
หากไฟล์ถูกเก็บไว้ใน BLOB ตามที่ระบุในคำถามคุณอาจไม่รู้จักนามสกุลไฟล์
หอยทากเครื่องกล

55
นามสกุลไฟล์ไม่ใช่วิธีที่เชื่อถือได้ในการกำหนดประเภท mime
Cerin

13
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan

4
ใน python 3.6 ใช้งานได้:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow

3
ในขณะที่ @cerin เป็นสิทธิที่นามสกุลไฟล์ที่จะไม่น่าเชื่อถือ, ฉันได้ค้นพบเพียงว่าถูกต้องของpython-magic(ตามที่แนะนำในคำตอบด้านบน) จะยิ่งลดลงได้รับการยืนยันโดยgithub.com/s3tools/s3cmd/issues/198 ดังนั้นmimetypesดูเหมือนจะเป็นผู้สมัครที่ดีกว่าสำหรับฉัน
danqing

46

วิธีที่น่าเชื่อถือมากกว่าการใช้ไลบรารี่ mimetypes คือการใช้แพ็คเกจ python-magic

import magic
m = magic.open(magic.MAGIC_MIME)
m.load()
m.file("/tmp/document.pdf")

นี่จะเทียบเท่ากับการใช้ไฟล์ (1)

ใน Django หนึ่งสามารถตรวจสอบให้แน่ใจว่าประเภท MIME ตรงกับประเภทอัพโหลดได้แล้ว content_type


2
ดูโพสต์ของ Simon Zimmermann สำหรับการใช้งาน python-magic ที่ได้รับการปรับปรุง
Daren Thomas

@DarenThomas: ดังที่ได้กล่าวไว้ในคำตอบของ mammadori คำตอบนี้ไม่ล้าสมัยและแตกต่างจากโซลูชันของ Simon Zimmermann หากคุณติดตั้งยูทิลิตี้ไฟล์ไว้คุณสามารถใช้วิธีนี้ได้ มันทำงานได้สำหรับฉันกับไฟล์ -5.32 ใน gentoo คุณต้องเปิดใช้งาน python USE-flag สำหรับแพ็คเกจไฟล์
bodo

36

ดูเหมือนจะง่ายมาก

>>> from mimetypes import MimeTypes
>>> import urllib 
>>> mime = MimeTypes()
>>> url = urllib.pathname2url('Upload.xml')
>>> mime_type = mime.guess_type(url)
>>> print mime_type
('application/xml', None)

โปรดอ้างอิงโพสต์เก่า

อัพเดท - ตามความคิดเห็นของ @Garrets ใน python 3 มันง่ายกว่ามาก:

import mimetypes
print(mimetypes.guess_type("sample.html"))

4
ฉันไม่คิดว่าจำเป็นต้องใช้ urllib ในตัวอย่างของคุณ
BrotherJack

5
สำหรับ Python 3.X แทนที่ urllib นำเข้าด้วยจากคำขอนำเข้า urllib และจากนั้นใช้ "คำขอ" แทน urllib
Arjun Thakur

1
ใช้งานได้กับ python 2.7 ด้วย
Jay Modi

โซลูชันของ @ oetzi ใช้โมดูลนี้ แต่ใช้ง่ายกว่า
Garrett

11

มี 3 ไลบรารีที่แตกต่างกันที่ล้อม libmagic

2 ของพวกเขามีอยู่ใน pypi (ดังนั้นการติดตั้ง pip จะทำงาน):

  • filemagic
  • หลามมายากล

และอีกอย่างที่คล้ายกับ python-magic นั้นมีอยู่ในแหล่ง libmagic ล่าสุดโดยตรงและมันก็เป็นสิ่งที่คุณมีในการแจกจ่าย linux ของคุณ

ใน Debian แพ็คเกจ python-magic เป็นเรื่องเกี่ยวกับสิ่งนี้และมันถูกใช้เป็น toivotuo กล่าวและมันไม่ล้าสมัยเหมือน Simon Zimmermann กล่าว (IMHO)

ดูเหมือนว่าฉันจะใช้อีก (โดยผู้เขียนต้นฉบับของ libmagic)

เลวร้ายเกินไปไม่สามารถใช้งานได้โดยตรงบน pypi


ฉันได้เพิ่ม repo เพื่อความสะดวก: github.com/mammadori/magic-python ในแบบที่คุณสามารถทำได้: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori

10

ในหลาม 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]

6
สิ่งนี้ไม่จำเป็นเนื่องจากfileคำสั่งนั้นเป็นเพียงตัวคลุมรอบ libmagic คุณอาจใช้เพียงแค่การผูก python (python-magic) เช่นเดียวกับในคำตอบของ Simon
หอยทากเครื่องกล

6
ขึ้นอยู่กับระบบปฏิบัติการ บน Mac OS X คุณมี "ไฟล์" แต่ไม่มี libmagic ในสภาพแวดล้อมปกติ
rptb1

9

2017 Update

ไม่จำเป็นต้องไปที่ GitHub มันอยู่ใน PyPi ภายใต้ชื่ออื่น:

pip3 install --user python-magic
# or:
sudo apt install python3-magic  # Ubuntu distro package

รหัสสามารถทำให้ง่ายขึ้นเช่นกัน:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'

คุณสามารถทำเช่นเดียวกันสำหรับไฟล์ js หรือ css ได้หรือไม่
kumbhanibhavesh

แน่นอนว่าทำไมไม่
Gringo Suave

9

Python เชื่อมโยงกับ libmagic

คำตอบที่แตกต่างกันทั้งหมดในหัวข้อนี้สับสนมากดังนั้นฉันหวังว่าจะให้ความกระจ่างกับภาพรวมของการเชื่อม libmagic ที่แตกต่างกันเล็กน้อย ก่อนหน้านี้ mammadori ให้คำตอบสั้น ๆกับรายการตัวเลือกที่มี

libmagic

เมื่อพิจารณาไฟล์ประเภท Mime, เครื่องมือของทางเลือกเป็นเพียงการเรียกfileและ back-end libmagicที่เรียกว่า (ดูหน้าแรกของโครงการ .) โครงการนี้ได้รับการพัฒนาในภาคเอกชน CVS-พื้นที่เก็บข้อมูล แต่มีการอ่านอย่างเดียวกระจกคอมไพล์บน GitHub

ตอนนี้เครื่องมือนี้ซึ่งคุณจะต้องใช้หากคุณต้องการใช้การผูก libmagic กับ python ใด ๆ มาพร้อมกับการผูก python ของมันเองfile-magicแล้ว ไม่มีเอกสารทุ่มเทมากสำหรับพวกเขา แต่คุณก็สามารถดูได้ที่หน้าคนของ man libmagicc-ห้องสมุด: การใช้งานพื้นฐานอธิบายไว้ในไฟล์ readme :

import magic

detected = magic.detect_from_filename('magic.py')
print 'Detected MIME type: {}'.format(detected.mime_type)
print 'Detected encoding: {}'.format(detected.encoding)
print 'Detected file type name: {}'.format(detected.name)

นอกจากนี้คุณยังสามารถใช้ห้องสมุดโดยการสร้างMagicวัตถุที่ใช้magic.open(flags)เป็นที่แสดงในไฟล์ตัวอย่าง

ทั้งtoivotuoและ ewr2san ใช้สิ่งเหล่านี้file-magicการรวมรวมอยู่ในfileเครื่องมือ พวกเขาถือว่าผิดพลาดโดยใช้python-magicแพ็คเกจ สิ่งนี้ดูเหมือนจะบ่งบอกว่าถ้าทั้งสองอย่างfileและได้python-magicรับการติดตั้งแล้วโมดูลไพ ธ อนจะmagicอ้างถึงตัวเก่า

หลามมายากล

นี่คือห้องสมุดที่ Simon Zimmermann พูดถึงในคำตอบของเขาและยังใช้โดยClaude COULOMBEและGringo Suaveด้วย

filemagic

บันทึก : โครงการนี้ได้รับการปรับปรุงล่าสุดในปี 2013!

เนื่องจากอยู่บนพื้นฐานเดียวกัน C-API, ห้องสมุดนี้มีความคล้ายคลึงกันบางคนที่มีรวมอยู่ในfile-magic libmagicมันถูกกล่าวถึงโดยmammadori เท่านั้นและไม่มีคำตอบอื่นใดที่ใช้มัน


7

วิธีการ @toivotuo ทำงานได้ดีที่สุดและน่าเชื่อถือที่สุดสำหรับฉันภายใต้ python3 เป้าหมายของฉันคือการระบุไฟล์ gzipped ที่ไม่มีนามสกุล. gz ที่เชื่อถือได้ ฉันติดตั้ง python3-magic

import magic

filename = "./datasets/test"

def file_mime_type(filename):
    m = magic.open(magic.MAGIC_MIME)
    m.load()
    return(m.file(filename))

print(file_mime_type(filename))

สำหรับไฟล์ gzipped จะส่งคืน: application / gzip; charset = ไบนารี

สำหรับไฟล์ txt ที่คลายซิป (ข้อมูล iostat): text / plain; charset = ASCII สหรัฐอเมริกา

สำหรับไฟล์ tar: application / x-tar; charset = ไบนารี

สำหรับไฟล์ bz2: application / x-bzip2; charset = ไบนารี

และสุดท้าย แต่ไม่ท้ายสุดสำหรับฉันไฟล์. zip: application / zip; charset = ไบนารี


7

python 3 อ้างอิง: https://docs.python.org/3.2/library/mimetypes.html

mimetypes.guess_type (url, เข้มงวด = True) เดาประเภทของไฟล์ตามชื่อไฟล์หรือ URL ที่กำหนดโดย url ค่าที่ส่งคืนคือ tuple (ชนิด, การเข้ารหัส) โดยที่ประเภทคือ None หากไม่สามารถเดาได้ (ส่วนต่อท้ายที่ขาดหายไปหรือไม่รู้จัก) หรือสตริงของรูปแบบ 'type / subtype' ซึ่งใช้งานได้สำหรับส่วนหัวชนิดเนื้อหา MIME

การเข้ารหัสไม่มีสำหรับการไม่เข้ารหัสหรือชื่อของโปรแกรมที่ใช้ในการเข้ารหัส (เช่นการบีบอัดหรือ gzip) การเข้ารหัสเหมาะสำหรับใช้เป็นส่วนหัวการเข้ารหัสเนื้อหาไม่ใช่ส่วนหัวการเข้ารหัสการถ่ายโอนเนื้อหา การแมปเป็นตารางขับเคลื่อน การต่อท้ายการเข้ารหัสจะคำนึงถึงขนาดตัวพิมพ์ พิมพ์ส่วนต่อท้ายจะลองใช้ตัวพิมพ์เล็กและตัวพิมพ์เล็ก

อาร์กิวเมนต์ตัวเลือกที่เข้มงวดคือการตั้งค่าสถานะเพื่อระบุว่ารายการประเภท MIME ที่รู้จักนั้น จำกัด เฉพาะประเภทอย่างเป็นทางการที่ลงทะเบียนกับ IANA เมื่อเข้มงวดเป็น True (ค่าเริ่มต้น) สนับสนุนประเภท IANA เท่านั้น เมื่อเข้มงวดเป็นเท็จจะมีการรับรู้ประเภท MIME เพิ่มเติมที่ไม่ได้มาตรฐาน แต่ที่ใช้กันทั่วไป

import mimetypes
print(mimetypes.guess_type("sample.html"))

6

คุณไม่ได้ระบุว่าคุณใช้เว็บเซิร์ฟเวอร์ใด แต่ Apache มีโมดูลเล็ก ๆ ที่เรียกว่าMime Magicซึ่งใช้เพื่อระบุประเภทของไฟล์เมื่อถูกบอกให้ทำเช่นนั้น มันอ่านเนื้อหาของไฟล์บางส่วนและพยายามที่จะคิดออกว่ามันจะขึ้นอยู่กับตัวละครที่พบ และดังที่Dave Webb พูดถึง Mimetypes โมดูลภายใต้หลามจะทำงานให้ขยายเป็นประโยชน์

หรือถ้าคุณนั่งบนกล่อง UNIX คุณสามารถใช้sys.popen('file -i ' + fileName, mode='r')เพื่อคว้าประเภท MIME Windows ควรมีคำสั่งที่เทียบเท่า แต่ฉันไม่แน่ใจว่ามันคืออะไร


7
ทุกวันนี้คุณสามารถทำ subprocess.check_output (['file', '-b', '--mime', filename])
Nathan Villaescusa

ไม่มีเหตุผลจริงๆที่จะหันไปใช้เครื่องมือภายนอกเมื่อ python-magic ทำสิ่งที่เทียบเท่าได้ทุกอย่างถูกห่อหุ้มและอบอุ่น
damd

4

ใน Python 3.x และ webapp ที่มี url เป็นไฟล์ซึ่งไม่สามารถมีนามสกุลหรือนามสกุลปลอมได้ คุณควรติดตั้ง python-magic โดยใช้

pip3 install python-magic

สำหรับ Mac OS X คุณควรติดตั้ง libmagic ด้วย

brew install libmagic

ข้อมูลโค้ด

import urllib
import magic
from urllib.request import urlopen

url = "http://...url to the file ..."
request = urllib.request.Request(url)
response = urlopen(request)
mime_type = magic.from_buffer(response.readline())
print(mime_type)

หรือคุณสามารถใส่ขนาดลงในการอ่าน

import urllib
import magic
from urllib.request import urlopen

url = "http://...url to the file ..."
request = urllib.request.Request(url)
response = urlopen(request)
mime_type = magic.from_buffer(response.read(128))
print(mime_type)

มันจะโหลดไฟล์ทั้งหมดหรือไม่
吴毅凡

ไม่มันเป็นกระแสดังนั้นโดยปกติจะมีเพียงไม่กี่ไบต์
คลอดด์ COULOMBE

ฉันแก้ไขโดย response.readline () หรือ response.read (128) ขอบคุณ!
คลอดด์ COULOMBE

3

ฉันลอง mimetypes ไลบรารี่ก่อน ถ้ามันไม่ทำงานฉันก็ใช้ python-magic libary แทน

import mimetypes
def guess_type(filename, buffer=None):
mimetype, encoding = mimetypes.guess_type(filename)
if mimetype is None:
    try:
        import magic
        if buffer:
            mimetype = magic.from_buffer(buffer, mime=True)
        else:
            mimetype = magic.from_file(filename, mime=True)
    except ImportError:
        pass
return mimetype

1

โมดูล mimetypes เพียงรู้จักประเภทไฟล์ตามนามสกุลไฟล์ หากคุณพยายามกู้ไฟล์ประเภทที่ไม่มีนามสกุลไฟล์ชนิดนั้นจะไม่ทำงาน


3
ฉันไม่คิดว่ามันเป็นเรื่องจริง ประเภท MIME นั้นเกี่ยวกับวิธีบอกคนอื่นเกี่ยวกับรูปแบบข้อมูลไม่ใช่เกี่ยวกับวิธีค้นหารูปแบบข้อมูลด้วยตัวเอง หากคุณใช้เครื่องมือที่คาดเดารูปแบบโดยยึดตามส่วนขยายและพิมพ์ประเภท MIME คุณจะไม่สามารถใช้เครื่องมือนั้นได้หากไม่มีนามสกุลไฟล์ แต่วิธีอื่น ๆ ในการเดารูปแบบก็เป็นไปได้เช่นกันโดยการตรวจสอบด้วยโปรแกรมแยกวิเคราะห์
erikbwork

1

ฉันประหลาดใจที่ไม่มีใครพูดถึงมันนอกจากPygmentsสามารถคาดเดาเกี่ยวกับประเภทข้อความโดยเฉพาะอย่างยิ่งเอกสารข้อความ

Pygments จริงแล้วเป็น Python เน้นไวยากรณ์ของไลบรารี่ แต่มีวิธีการที่จะทำการเดาที่มีการศึกษาเกี่ยวกับเอกสารที่รองรับ 500 ประเภทซึ่งเอกสารของคุณคือ เช่น c ++ กับ C # เทียบกับ Python กับ ฯลฯ

import inspect

def _test(text: str):
    from pygments.lexers import guess_lexer
    lexer = guess_lexer(text)
    mimetype = lexer.mimetypes[0] if lexer.mimetypes else None
    print(mimetype)

if __name__ == "__main__":
    # Set the text to the actual defintion of _test(...) above
    text = inspect.getsource(_test)
    print('Text:')
    print(text)
    print()
    print('Result:')
    _test(text)

เอาท์พุท:

Text:
def _test(text: str):
    from pygments.lexers import guess_lexer
    lexer = guess_lexer(text)
    mimetype = lexer.mimetypes[0] if lexer.mimetypes else None
    print(mimetype)


Result:
text/x-python

ตอนนี้มันไม่สมบูรณ์แบบ แต่ถ้าคุณต้องการที่จะบอกได้ว่ามีการใช้รูปแบบเอกสารใดใน 500 รูปแบบนี่เป็นสิ่งที่มีประโยชน์


0

ฉันลองตัวอย่างมากมาย แต่ด้วย Django mutagen ที่เล่นได้ดี

ตัวอย่างการตรวจสอบว่าไฟล์เป็น mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

try:
    audio = MP3(file)
except HeaderNotFoundError:
    raise ValidationError('This file should be mp3')

ข้อเสียคือความสามารถในการตรวจสอบประเภทของไฟล์ของคุณมี จำกัด แต่เป็นวิธีที่ดีถ้าคุณไม่เพียง แต่ต้องการตรวจสอบประเภทของไฟล์ แต่ยังเข้าถึงข้อมูลเพิ่มเติมอีกด้วย


ฉันต้องตรวจสอบความปลอดภัยด้วย
Artem Bernatskyi


0

สำหรับข้อมูลประเภทไบต์อาร์เรย์คุณสามารถใช้ magic.from_buffer (_byte_array, mime = True)


-1

คุณสามารถใช้โมดูลimghdr Python


1
นี่ไม่ใช่ความคิดเห็นที่เป็นประโยชน์เพราะมันไม่ได้ยกตัวอย่างหรือไม่ได้บอกว่าทำไมหรืออย่างไรทำไม imghdr ถึงช่วยได้ที่นี่
erikbwork

2
ใช่ฉันเข้าใจแล้ว เป็นเวลาหนึ่งปีที่ผ่านมา แต่บางทีคุณยังสามารถอัปเดตได้เพราะยังมีคนที่ค้นหาคำถามนี้เช่นฉัน หากคุณต้องการความช่วยเหลือคุณสามารถบอกฉันได้
erikbwork

1
ใช้งานได้กับรายการประเภทภาพที่ จำกัด เท่านั้น มันไม่มีความคิดเกี่ยวกับไฟล์ข้อความ, ไฟล์บีบอัด, รูปแบบเอกสาร, ฯลฯ
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.