[python] 파이썬과 BeautifulSoup를 사용하여 웹 페이지에서 링크를 검색


Answers

다른 사람들은 BeautifulSoup을 추천했지만, lxml 을 사용하는 것이 훨씬 낫습니다. 그것의 이름에도 불구하고, 그것은 또한 HTML을 분석하고 긁는 것입니다. 그것은 BeautifulSoup보다 훨씬 빠르고 빠르며 BeautifulSoup (명성을 얻으려는 주장)보다 "고장난"HTML을 잘 처리합니다. lxml API를 배우고 싶지 않은 경우 BeautifulSoup에 대한 호환 API도 있습니다.

Ian Blicking도 동의합니다 .

Google App Engine 또는 순수한 Python이 허용되지 않는 곳을 제외하고는 BeautifulSoup을 더 이상 사용할 필요가 없습니다.

lxml.html은 CSS3 셀렉터를 지원하므로 이런 일은 사소한 일이다.

lxml 및 xpath를 사용한 예는 다음과 같습니다.

import urllib
import lxml.html
connection = urllib.urlopen('http://www.nytimes.com')

dom =  lxml.html.fromstring(connection.read())

for link in dom.xpath('//a/@href'): # select the url in href for all a tags(links)
    print link
Question

웹 페이지의 링크를 검색하고 파이썬을 사용하여 링크의 URL 주소를 복사하려면 어떻게해야합니까?




import urllib2
import BeautifulSoup

request = urllib2.Request("http://www.gpsbasecamp.com/national-parks")
response = urllib2.urlopen(request)
soup = BeautifulSoup.BeautifulSoup(response)
for a in soup.findAll('a'):
  if 'national-park' in a['href']:
    print 'found a url with national-park in the link'



BeatifulSoup의 파서는 느려질 수 있습니다. URL에서 직접 파싱 할 수있는 lxml 을 사용하는 것이 더 적합 할 수 있습니다 (아래 언급 된 몇 가지 제한 사항이 있음).

import lxml.html

doc = lxml.html.parse(url)

links = doc.xpath('//a[@href]')

for link in links:
    print link.attrib['href']

위의 코드는 링크를 그대로 반환하며, 대부분의 경우 상대 링크이거나 사이트 루트의 절대 경로입니다. 필자의 사용 사례는 특정 유형의 링크 만 추출하기 때문에 아래 링크는 링크를 전체 URL로 변환하고 선택적으로 *.mp3 과 같은 glob 패턴을 허용하는 버전입니다. 그것은 상대 경로에서 싱글과 더블 점을 처리하지는 않지만, 지금까지 나는 그것을 필요가 없었습니다. ../ 또는 ./ 을 포함하는 URL 조각을 구문 분석해야하는 경우 urlparse.urljoin 이 유용 할 수 있습니다.

참고 : 직접 lxml url 구문 분석은 https 에서로드를 처리하지 않으며 리디렉션을하지 않으므로 아래 버전에서는 urllib2 + lxml 있습니다.

#!/usr/bin/env python
import sys
import urllib2
import urlparse
import lxml.html
import fnmatch

try:
    import urltools as urltools
except ImportError:
    sys.stderr.write('To normalize URLs run: `pip install urltools --user`')
    urltools = None


def get_host(url):
    p = urlparse.urlparse(url)
    return "{}://{}".format(p.scheme, p.netloc)


if __name__ == '__main__':
    url = sys.argv[1]
    host = get_host(url)
    glob_patt = len(sys.argv) > 2 and sys.argv[2] or '*'

    doc = lxml.html.parse(urllib2.urlopen(url))
    links = doc.xpath('//a[@href]')

    for link in links:
        href = link.attrib['href']

        if fnmatch.fnmatch(href, glob_patt):

            if not href.startswith(('http://', 'https://' 'ftp://')):

                if href.startswith('/'):
                    href = host + href
                else:
                    parent_url = url.rsplit('/', 1)[0]
                    href = urlparse.urljoin(parent_url, href)

                    if urltools:
                        href = urltools.normalize(href)

            print href

사용법은 다음과 같습니다.

getlinks.py http://.com/a/37758066/191246
getlinks.py http://.com/a/37758066/191246 "*users*"
getlinks.py http://fakedomain.mu/somepage.html "*.mp3"



B.soup와 regex없이 링크를 얻는 것만으로 :

import urllib2
url="http://www.somewhere.com"
page=urllib2.urlopen(url)
data=page.read().split("</a>")
tag="<a href=\""
endtag="\">"
for item in data:
    if "<a href" in item:
        try:
            ind = item.index(tag)
            item=item[ind+len(tag):]
            end=item.index(endtag)
        except: pass
        else:
            print item[:end]

더 복잡한 작업을 위해서는 BSoup가 여전히 선호됩니다.




정규 표현식을 사용하지 않는 이유 :

import urllib2
import re
url = "http://www.somewhere.com"
page = urllib2.urlopen(url)
page = page.read()
links = re.findall(r"<a.*?\s*href=\"(.*?)\".*?>(.*?)</a>", page)
for link in links:
    print('href: %s, HTML text: %s' % (link[0], link[1]))



@ Blairg23에 의해 다음 정정 (올바르게 작동하지 못한 시나리오 포함) 이후에 해답을 찾았습니다.

for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        if file_type in link['href']:
            full_path =urlparse.urljoin(url , link['href']) #module urlparse need to be imported
            wget.download(full_path)

파이썬 3 :

urllib.parse.urljoin 을 사용하여 전체 URL을 가져와야합니다.




후드 아래 BeautifulSoup은 이제 lxml을 사용합니다. 요청, lxml 및 목록 포함은 킬러 콤보를 만듭니다.

import requests
import lxml.html

dom = lxml.html.fromstring(requests.get('http://www.nytimes.com').content)

[x for x in dom.xpath('//a/@href') if '//' in x and 'nytimes.com' not in x]

목록 comp에서 "if '//'및 'url.com'이 x에없는"은 사이트의 내부 탐색 URL 등의 URL 목록을 삭제하는 간단한 방법입니다.




Related