2017-04-18 5 views
1

http://www.apkmirror.com (예 : http://www.apkmirror.com/apk/google-inc/gmail/gmail-7-3-26-152772569-release-release/gmail-7-3-26-152772569-release-android-apk-download/)의 APK 다운로드 페이지를 구문 분석하려고합니다. package으로 내가 architecture으로 "팔", version_code으로 "17329196"을 구문 분석 할PyParsing에서 Word가 주어진 리터럴과 동일하지 않도록 지정하는 방법은 무엇입니까?

enter image description here

, 그리고 "com.skype.m2"일반적으로 "APK보기 '섹션에는 다음과 같은 구조를 가지고 있습니다. 그러나 때로는 architecture있는 라인은 아래 그림과 같이 누락되었습니다

enter image description here

을 지금까지, 선택과 Scrapy를 사용

apk_details = response.xpath('//*[@title="APK details"]/following-sibling::*[@class="appspec-value"]//text()').extract() 

나는 수의 압축을 풉니 '라인을 포함하는 목록을 봤는데 '위에 표시됩니다. 나는 다음과 같은 테스트를 통과하도록하는 기능 parse_apk_details를 작성하려고 해요 : 위의 주석으로

import pytest 

def test_parse_apk_details_with_architecture(): 
    apk_details = [u'Version: 3.0.38_ww (4030038)', 
        u'arm ', 
        u'Package: com.lenovo.anyshare.gps', 
        u'\n', 
        u'2,239 downloads '] 

    version_code, architecture, package = parse_apk_details(apk_details) 

    assert version_code == 4030038 
    assert architecture == "arm" 
    assert package == "com.lenovo.anyshare.gps" 

@pytest.mark.skip(reason="This does not work yet, because 'Package:' is interpreted by the parser as the architecture.") 
def test_parse_apk_details_without_architecture(): 
    apk_details = [u'Version: 3.0.38_ww (4030038)', 
        u'Package: com.lenovo.anyshare.gps', 
        u'\n', 
        u'2,239 downloads '] 

    version_code, architecture, package = parse_apk_details(apk_details) 

    assert version_code == 4030038 
    assert package == "com.lenovo.anyshare.gps" 


if __name__ == "__main__": 
    pytest.main([__file__]) 

그러나, 두 번째 테스트가 아직 전달하지 않습니다.

from pyparsing import Word, printables, nums, Optional 

def parse_apk_details(apk_details): 
    apk_details = "\n".join(apk_details) # The newline character is ignored by PyParsing (by default) 
    version_name = Word(printables)   # The version name can consist of all printable, non-whitespace characters 
    version_code = Word(nums)    # The version code is expected to be an integer 
    architecture = Word(printables) 
    package = Word(printables) 

    expression = "Version:" + version_name + "(" + version_code("version_code") + ")" + Optional(architecture("architecture")) + "Package:" + package("package") 
    result = expression.parseString(apk_details) 

    return int(result.get("version_code")), result.get("architecture"), result.get("package") 

내가 두 번째 테스트를 실행하려고하면 내가 오류는 다음과 같습니다 :입니다 :

ParseException: Expected "Package:" (at char 38), (line:2, col:10) 

내가 무슨 일이 일어나고하는 일 "패키지"라는 것을 믿고 여기까지 기능입니다 architecture으로 '소비'됩니다. 이 문제를 해결하는 한 가지 방법은 라인 architecture = Word(printables)을 (의사 코드로) architecture = Word(printables) + ~"Package:"과 같이 "Package :"라는 단어를 제외한 인쇄 가능한 문자로 구성 될 수 있음을 나타내는 것으로 변경하는 것입니다.

특정 단어가 "Package:"이 아닌 경우에만 architecture이 구문 분석되도록하려면 어떻게해야합니까? (원래 문제의 대안 scrapy 기반 솔루션에도 관심이 있습니다.)

답변

1

architecture = Word(printables) + ~Literal("Package:")과 정말 가까웠습니다. 부정적 예측하려면, 부정으로 시작, 다음 경기 :

architecture = ~Literal("Package:") + Word(printables) 
0

마침내 아키텍처 (예 : "arm")가 포함 된 줄의 다른 특성을 사용했습니다. 아키텍처에 줄 바꿈 문자가 있으면 그 뒤에 줄 문자가 오는 것입니다.

from pyparsing import Word, printables, nums, Optional, LineEnd, FollowedBy, Suppress 

def parse_apk_details(apk_details): 
    apk_details = "\n".join(apk_details) # The newline character is ignored by PyParsing (by default) 
    version_name = Word(printables).setResultsName("version")  # The version name can consist of all printable, non-whitespace characters 
    version_code = Word(nums).setResultsName("version_code")    # The version code is expected to be an integer 
    architecture = Word(printables).setResultsName("architecture") + Suppress(FollowedBy(LineEnd())) 
    package = Word(printables).setResultsName("package") 

    expression = "Version:" + version_name + "(" + version_code + ")" + Optional(architecture) + "Package:" + package 
    result = expression.parseString(apk_details) 

    return int(result.get("version_code")), result.get("architecture"), result.get("package") 

이 모두 테스트를 통과한다 : 나는 방법은 다음과 parse_apk_details을 개정.

+1

당신은 setResultsName''의 짧은 컷 양식을 사용할 수 있습니다 - 대신 VERSION_NAME = 워드 (printables)'의 .setResultsName ("버전") ' , 그냥'version_name = Word (printables) ("version")'이라고 써라. – PaulMcG