python爬取流媒体_m3u8:Python m3u8 HTTP流媒体直播(HLS)传输的解析器

m3u8

Python m3u8 parser.

Documentation

Loading a playlist

To load a playlist into an object from uri, file path or directly from string, use the load/loads functions:

import m3u8

playlist = m3u8.load('http://videoserver.com/playlist.m3u8') # this could also be an absolute filename

print(playlist.segments)

print(playlist.target_duration)

# if you already have the content as string, use

playlist = m3u8.loads('#EXTM3U8 ... etc ... ')

Dumping a playlist

To dump a playlist from an object to the console or a file, use the dump/dumps functions:

import m3u8

playlist = m3u8.load('http://videoserver.com/playlist.m3u8')

print(playlist.dumps())

# if you want to write a file from its content

playlist.dump('playlist.m3u8')

Supported tags

Encryption keys

The segments may be or not encrypted. The keys attribute list will be a list with all the different keys as described with #EXT-X-KEY:

Each key has the next properties:

method: ex.: "AES-128"

iv: the initialization vector, if available. Otherwise None.

If no #EXT-X-KEY is found, the keys list will have a unique element None. Multiple keys are supported.

If unencrypted and encrypted segments are mixed in the M3U8 file, then the list will contain a None element, with one or more keys afterwards.

To traverse the list of keys available:

import m3u8

m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')

len(m3u8_obj.keys) => returns the number of keys available in the list (normally 1)

for key in m3u8_obj.keys:

if key: # First one could be None

key.uri

key.method

key.iv

Getting segments encrypted with one key

There are cases where listing segments for a given key is important. It's possible to retrieve the list of segments encrypted with one key via by_key method in the segments list.

Example of getting the segments with no encryption:

import m3u8

m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')

segmk1 = m3u8_obj.segments.by_key(None)

# Get the list of segments encrypted using last key

segm = m3u8_obj.segments.by_key( m3u8_obj.keys[-1] )

With this method, is now possible also to change the key from some of the segments programmatically:

import m3u8

m3u8_obj = m3u8.loads('#EXTM3U8 ... etc ...')

# Create a new Key and replace it

new_key = m3u8.Key("AES-128", "/encrypted/newkey.bin", None, iv="0xf123ad23f22e441098aa87ee")

for segment in m3u8_obj.segments.by_key( m3u8_obj.keys[-1] ):

segm.key = new_key

# Remember to sync the key from the list as well

m3u8_obj.keys[-1] = new_key

Variant playlists (variable bitrates)

A playlist can have a list to other playlist files, this is used to represent multiple bitrates videos, and it's called variant streams. See an example here.

variant_m3u8 = m3u8.loads('#EXTM3U8 ... contains a variant stream ...')

variant_m3u8.is_variant # in this case will be True

for playlist in variant_m3u8.playlists:

playlist.uri

playlist.stream_info.bandwidth

the playlist object used in the for loop above has a few attributes:

uri: the url to the stream

stream_info: a StreamInfo object (actually a namedtuple) with all the attributes available to #EXT-X-STREAM-INF

media: a list of related Media objects with all the attributes available to #EXT-X-MEDIA

playlist_type: the type of the playlist, which can be one of VOD (video on demand) or EVENT

NOTE: the following attributes are not implemented yet, follow issue 4 for updates

alternative_audios: its an empty list, unless it's a playlist with Alternative audio, in this case it's a list with Media objects with all the attributes available to #EXT-X-MEDIA

alternative_videos: same as alternative_audios

A variant playlist can also have links to I-frame playlists, which are used to specify where the I-frames are in a video. See Apple's documentation on this for more information. These I-frame playlists can be accessed in a similar way to regular playlists.

variant_m3u8 = m3u8.loads('#EXTM3U ... contains a variant stream ...')

for iframe_playlist in variant_m3u8.iframe_playlists:

iframe_playlist.uri

iframe_playlist.iframe_stream_info.bandwidth

The iframe_playlist object used in the for loop above has a few attributes:

uri: the url to the I-frame playlist

base_uri: the base uri of the variant playlist (if given)

iframe_stream_info: a StreamInfo object (same as a regular playlist)

Custom tags

Quoting the documentation:

Lines that start with the character '#' are either comments or tags.

Tags begin with #EXT. They are case-sensitive. All other lines that

begin with '#' are comments and SHOULD be ignored.

This library ignores all the non standard tags by default. If you want them to be collected while loading the file content, you need to pass a function to the load/loads functions, following the example below:

import m3u8

def get_movie(line, data, lineno):

if line.startswith('#MOVIE-NAME:'):

custom_tag = line.split(':')

data['movie'] = custom_tag[1].strip()

m3u8_obj = m3u8.load('http://videoserver.com/playlist.m3u8', custom_tags_parser=get_movie)

print(m3u8_obj.data['movie']) # million dollar baby

Using different HTTP clients

If you don't want to use urllib to download playlists, having more control on how objects are fetched over the internet, you can use your own client. requests is a well known Python HTTP library and it can be used with m3u8:

import m3u8

import requests

class RequestsClient():

def download(self, uri, timeout=None, headers={}, verify_ssl=True):

o = requests.get(uri, timeout=timeout, headers=headers)

return o.text, o.url

playlist = m3u8.load('http://videoserver.com/playlist.m3u8', http_client=RequestsClient())

print(playlist.dumps())

The advantage of using a custom HTTP client is to refine SSL verification, proxies, performance, flexibility, etc.

Playlists behind proxies

In case you need to use a proxy but can't use a system wide proxy (HTTP/HTTPS proxy environment variables), you can pass your HTTP/HTTPS proxies as a dict to the load function.

import m3u8

proxies = {

'http': 'http://10.10.1.10:3128',

'https': 'http://10.10.1.10:1080',

}

http_client = m3u8.httpclient.DefaultHTTPClient(proxies)

playlist = m3u8.load('http://videoserver.com/playlist.m3u8', http_client=http_client) # this could also be an absolute filename

print(playlist.dumps())

It works with the default client only. Custom HTTP clients must implement this feature.

Running Tests

$ ./runtests

Contributing

All contribution is welcome, but we will merge a pull request if, and only if, it

has tests

follows the code conventions

If you plan to implement a new feature or something that will take more than a few minutes, please open an issue to make sure we don't work on the same thing.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值