몇 가지 기술적 인 문제가 귀하의 질문에 있습니다.
먼저 서버에 연결하고 데이터를 검색하는 간단한 문제입니다. 아래의 connect()
에서 볼 수 있듯이 매우 간단합니다. 소켓 (s = socket.socket()
)을 만들고 연결하십시오 (s.connect(('hostname', port_number))
).
다음 문제는 유용한 양식으로 데이터를 검색하는 것입니다. 소켓은 기본적으로 .recv()
을 제공하지만 파일과 비슷한 인터페이스로 무언가를 원했습니다. 소켓 모듈은 파이썬 고유의 메소드 인 .makefile()
을 제공합니다. (return s.makefile('rb')
)
이제 우리는 어려운 부분에 도달합니다. XML 문서는 일반적으로 파일 당 하나의 문서 또는 TCP 전송 당 하나의 문서로 저장됩니다. 따라서 문서의 끝은 파일 끝 표시 또는 Content-Length:
헤더로 쉽게 발견 할 수 있습니다. 결과적으로 파이썬 XML API는 하나의 파일이나 하나의 문자열에서 여러 XML 문서를 다루는 메커니즘을 가지고 있지 않다. 나는이 문제를 해결하기 위해 xml_partition()
라고 썼다. xml_partition()
은 파일과 유사한 객체에서 데이터를 사용하고 스트림에서 각 XML 문서를 생성합니다. (참고 : XML 문서는 함께 눌러야하며, 마지막 공백 뒤에는 공백이 허용되지 않습니다. >
).
마지막으로 간단한 테스트 프로그램 (alerts()
)이 스트림에 연결되고 몇 개의 XML 문서를 읽고 각 파일을 자체 파일에 저장합니다.
여기 전체적으로 Pelmorex의 National Alert Aggregation & 보급 시스템에서 긴급 알리미를 다운로드하는 프로그램입니다.
import socket
import xml.etree.ElementTree as ET
def connect():
'Connect to pelmorex data stream and return a file-like object'
# Set up the socket
s = socket.socket()
s.connect(('streaming1.naad-adna.pelmorex.com', 8080))
return s.makefile('rb')
# We have to consume the XML data in bits and pieces
# so that we can stop precisely at the boundary between
# streamed XML documents. This function ensures that
# nothing follows a '>' in any XML fragment.
def partition(s, pattern):
'Consume a file-like object, and yield parts defined by pattern'
data = s.read(2048)
while data:
left, middle, data = data.partition(pattern)
while left or middle:
yield left
yield middle
left, middle, data = data.partition(pattern)
data = s.read(2048)
# Split the incoming XML stream into fragments (much smaller
# than an XML document.) The end of each XML document
# is guaranteed to align with the end of a fragment.
# Use an XML parser to determine the actual end of
# a document. Whenever the parser signals the end
# of an XML document, yield what we have so far and
# start a new parser.
def xml_partition(s):
'Read multiple XML documents from one data stream'
parser = None
for part in partition(s, b'>'):
if parser is None:
parser = ET.XMLPullParser(['start', 'end'])
starts = ends = 0
xml = []
xml.append(part)
parser.feed(part)
for event, elem in parser.read_events():
starts += event == "start"
ends += event == "end"
if starts == ends > 0:
# We have reached the end of the XML doc
parser.close()
parser = None
yield b''.join(xml)
# Typical usage:
def alerts():
for i, xml in enumerate(xml_partition(connect())):
# The XML is a bytes object that contains the undecoded
# XML stream. You'll probably want to parse it and
# somehow display the alert.
# I'm just saving it to a file.
with open('alert%d.xml' % i, 'wb') as fp:
fp.write(xml)
if i == 3:
break
def test():
# A test function that uses multiple XML documents in one
# file. This avoids the wait for a natural-disaster alert.
with open('multi.xml', 'rb') as fp:
print(list(xml_partition(fp)))
alerts()
"TCP 피드"는 컴퓨터 네트워킹 분야의 용어는 아닙니다. 당신의 질문에 더 정확하게 할 수 있습니까? –
@ Robᵩ 나는 그 게시물에 대한 자세한 내용을 추가했습니다. 처음에는 명확하지 않다는 것에 대해 유감스럽게 생각합니다. – maldahleh