programing

Python 및 BeautifulSoup을 사용하여 웹 페이지에서 링크 검색

showcode 2023. 6. 14. 21:58
반응형

Python 및 BeautifulSoup을 사용하여 웹 페이지에서 링크 검색

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

다음은 BeautifulSoup의 SoupStrainer 클래스를 사용한 짧은 토막글입니다.

import httplib2
from bs4 import BeautifulSoup, SoupStrainer

http = httplib2.Http()
status, response = http.request('http://www.nytimes.com')

for link in BeautifulSoup(response, parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        print(link['href'])

BeautifulSoup 설명서는 실제로 매우 유용하며 다음과 같은 일반적인 시나리오를 다룹니다.

https://www.crummy.com/software/BeautifulSoup/bs4/doc/

편집: SoupStrainer 클래스를 사용한 이유는 구문 분석하는 내용을 미리 알고 있다면 이 클래스가 좀 더 효율적이기 때문입니다.

완전성을 위해 BeautifulSoup 4 버전은 서버에서 제공하는 인코딩도 사용합니다.

from bs4 import BeautifulSoup
import urllib.request

parser = 'html.parser'  # or 'lxml' (preferred) or 'html5lib', if installed
resp = urllib.request.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, parser, from_encoding=resp.info().get_param('charset'))

for link in soup.find_all('a', href=True):
    print(link['href'])

또는 Python 2 버전:

from bs4 import BeautifulSoup
import urllib2

parser = 'html.parser'  # or 'lxml' (preferred) or 'html5lib', if installed
resp = urllib2.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, parser, from_encoding=resp.info().getparam('charset'))

for link in soup.find_all('a', href=True):
    print link['href']

라이브러리를 사용하는 버전으로, 작성된 대로 Python 2와 3 모두에서 작동합니다.

from bs4 import BeautifulSoup
from bs4.dammit import EncodingDetector
import requests

parser = 'html.parser'  # or 'lxml' (preferred) or 'html5lib', if installed
resp = requests.get("http://www.gpsbasecamp.com/national-parks")
http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True)
encoding = html_encoding or http_encoding
soup = BeautifulSoup(resp.content, parser, from_encoding=encoding)

for link in soup.find_all('a', href=True):
    print(link['href'])

soup.find_all('a', href=True) 은 모두를 .<a>가된요가 있는 href특성: 특성이 없는 요소는 건너뜁니다.

BeautifulSoup 3는 2012년 3월에 개발을 중단했습니다. 새로운 프로젝트는 BeautifulSoup 4를 항상 사용해야 합니다.

HTML을 바이트에서 BeautifulSoup으로 디코딩하는 것은 그대로 두어야 합니다.디코딩을 지원하기 위해 HTTP 응답 헤더에 있는 문자 집합을 BeautifulSoup에 알릴 수 있지만, 는 잘못된 것이며 다음과 충돌할 수 있습니다.<meta>자체에서 메서드 HTML을 입니다. 이것이 위에서 BeautifulSoup 내부 클래스 메서드를 사용하는 이유입니다.EncodingDetector.find_declared_encoding()이러한 내장 인코딩 힌트가 잘못 구성된 서버를 이기도록 합니다.

와 함께requests,response.encoding에 Latin-1과 Latin-1이 하는 경우 로 설정됩니다.text/*문자 집합이 반환되지 않은 경우에도 mimtype입니다.구문 분석과 할 때 " " HTTP RFC " " HTML " " ", " ", " " 이 없을 .charset내용 유형 헤더에 설정됩니다.

다른 사람들은 BeautifulSoup을 추천했지만, lxml을 사용하는 것이 훨씬 좋습니다.이름에도 불구하고 HTML을 구문 분석하고 스크레이핑하기 위한 용도이기도 합니다.BeautifulSoup보다 훨씬 빠르고 심지어 BeautifulSoup(그들의 명성 주장)보다 "깨진" HTML을 더 잘 처리합니다.lxml API를 배우고 싶지 않다면 BeautifulSoup용 호환 API도 있습니다.

이안 블릭도 동의합니다.

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
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'

다음 코드는 웹 페이지에서 사용 가능한 모든 링크를 검색하는 것입니다.urllib2그리고.BeautifulSoup4:

import urllib2
from bs4 import BeautifulSoup

url = urllib2.urlopen("http://www.espncricinfo.com/").read()
soup = BeautifulSoup(url)

for line in soup.find_all('a'):
    print(line.get('href'))

링크는 다양한 속성 내에 있을 수 있으므로 해당 속성의 목록을 전달할 수 있습니다.select.

예를 들어 다음과 같이src그리고.href속성(여기서는 starts with ^ 연산자를 사용하여 이러한 속성 값 중 하나가 http로 시작하도록 지정합니다):

from bs4 import BeautifulSoup as bs
import requests
r = requests.get('https://stackoverflow.com/')
soup = bs(r.content, 'lxml')
links = [item['href'] if item.get('href') is not None else item['src'] for item in soup.select('[href^="http"], [src^="http"]') ]
print(links)

속성 = 값 선택기

[attr^=value]

값이 값 앞에 붙는(앞에) 특성 이름을 가진 요소를 나타냅니다.

일반적으로 사용되는 것도 있습니다.$(으로 끝남) 및*연산자전체 구문 목록은 위의 링크를 참조하십시오.

후드 아래에서 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]

리스트 컴프에서 "만약 x에 없는 '//'와 'url.com '은 사이트 '내부' 탐색 URL 등의 URL 목록을 스크럽하는 간단한 방법입니다.

이 스크립트는 원하는 작업을 수행하지만 절대 링크에 대한 상대적 링크도 해결합니다.

import urllib
import lxml.html
import urlparse

def get_dom(url):
    connection = urllib.urlopen(url)
    return lxml.html.fromstring(connection.read())

def get_links(url):
    return resolve_links((link for link in get_dom(url).xpath('//a/@href')))

def guess_root(links):
    for link in links:
        if link.startswith('http'):
            parsed_link = urlparse.urlparse(link)
            scheme = parsed_link.scheme + '://'
            netloc = parsed_link.netloc
            return scheme + netloc

def resolve_links(links):
    root = guess_root(links)
    for link in links:
        if not link.startswith('http'):
            link = urlparse.urljoin(root, link)
        yield link  

for link in get_links('http://www.google.com'):
    print link

모든 링크를 찾기 위해 예에서는 urllib2 모듈을 re.module과 함께 사용합니다. *리모듈에서 가장 강력한 기능 중 하나는 "re.findall()"입니다.re.search()를 사용하여 패턴에 대한 첫 번째 일치 항목을 찾는 동안 re.findall()은 모든 일치 항목을 찾아 각 문자열이 하나의 일치 항목을 나타내는 문자열 목록으로 반환합니다.*

import urllib2

import re
#connect to a URL
website = urllib2.urlopen(url)

#read html code
html = website.read()

#use re.findall to get all the links
links = re.findall('"((http|ftp)s?://.*?)"', html)

print links

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]

더 복잡한 운영을 위해서는 물론 B 수프가 여전히 선호됩니다.

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

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]))

다음은 @ars accepted answer를 사용한 예입니다.BeautifulSoup4,requests,그리고.wget다운로드를 처리할 모듈을 선택합니다.

import requests
import wget
import os

from bs4 import BeautifulSoup, SoupStrainer

url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/eeg-mld/eeg_full/'
file_type = '.tar.gz'

response = requests.get(url)

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 = url + link['href']
            wget.download(full_path)

저는 다음과 같은 수정 후에 @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)

Python 3의 경우:

urllib.parse.urljoin대신 전체 URL을 가져오려면 를 사용해야 합니다.

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상대 경로에서 단일 점과 이중 점을 처리할 수는 없지만, 지금까지는 그럴 필요가 없었습니다. 함는하 URL 구분문석이 포함된 URL 를 구문 ../또는./그러면 urlparse.urljoin이 도움이 될 수 있습니다.

참고: Direct lxml URL 구문 분석에서 로드를 처리하지 않습니다.https은 그고리디션수행지않으이로므이다사아용니됩버전이래리유로러한을렉하▁using▁below▁and다▁is▁version를 사용하고 있습니다.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://stackoverflow.com/a/37758066/191246
getlinks.py http://stackoverflow.com/a/37758066/191246 "*users*"
getlinks.py http://fakedomain.mu/somepage.html "*.mp3"

외부 및 내부 링크와 함께 많은 중복 링크가 있을 수 있습니다.두 가지를 구분하고 세트를 사용하여 고유한 링크를 얻는 방법:

# Python 3.
import urllib    
from bs4 import BeautifulSoup

url = "http://www.espncricinfo.com/"
resp = urllib.request.urlopen(url)
# Get server encoding per recommendation of Martijn Pieters.
soup = BeautifulSoup(resp, from_encoding=resp.info().get_param('charset'))  
external_links = set()
internal_links = set()
for line in soup.find_all('a'):
    link = line.get('href')
    if not link:
        continue
    if link.startswith('http'):
        external_links.add(link)
    else:
        internal_links.add(link)

# Depending on usage, full internal links may be preferred.
full_internal_links = {
    urllib.parse.urljoin(url, internal_link) 
    for internal_link in internal_links
}

# Print all unique external and full internal links.
for link in external_links.union(full_internal_links):
    print(link)
import urllib2
from bs4 import BeautifulSoup
a=urllib2.urlopen('http://dir.yahoo.com')
code=a.read()
soup=BeautifulSoup(code)
links=soup.findAll("a")
#To get href part alone
print links[0].attrs['href']

언급URL : https://stackoverflow.com/questions/1080411/retrieve-links-from-web-page-using-python-and-beautifulsoup

반응형