【问题标题】:What's the best way to scrape and plot connected pages on a website with Python?使用 Python 在网站上抓取和绘制连接页面的最佳方法是什么?
【发布时间】:2020-06-22 18:00:10
【问题描述】:

我一直在从事一个项目,该项目接受一个 url 输入并在网站上创建页面连接图。

我解决这个问题的方法是从页面中获取链接,然后创建一个页面对象来保存页面的 href 以及该页面上所有子链接的列表。从网站上的所有页面中提取数据后,我会将其传递给 matplotlib 或 plotly 之类的图形函数,以获得网站上页面之间连接的图形表示。

这是我目前的代码:

from urllib.request import urlopen
import urllib.error
from bs4 import BeautifulSoup, SoupStrainer

#object to hold page href and child links on page
class Page:

    def __init__(self, href, links):
        self.href = href
        self.children = links

    def getHref(self):
        return self.href

    def getChildren(self):
        return self.children


#method to get an array of all hrefs on a page
def getPages(url):
    allLinks = []

    try:
        #combine the starting url and the new href
        page = urlopen('{}{}'.format(startPage, url))
        for link in BeautifulSoup(page, 'html.parser', parse_only=SoupStrainer('a')):
            try:
                if 'href' in link.attrs:
                    allLinks.append(link)
            except AttributeError:
                #if there is no href, skip the link
                continue
            
        #return an array of all the links on the page
        return allLinks

    #catch pages that can't be opened
    except urllib.error.HTTPError:
        print('Could not open {}{}'.format(startPage, url))
    

#get starting page url from user
startPage = input('Enter a URL: ')
page = urlopen(startPage)

#sets to hold unique hrefs and page objects
pages = set()
pageObj = set()

for link in BeautifulSoup(page, 'html.parser', parse_only=SoupStrainer('a')):
    try:
        if 'href' in link.attrs:
            if link.attrs['href'] not in pages:
                newPage = link.attrs['href']
                pages.add(newPage)

                #get the child links on this page
                pageChildren = getPages(newPage)

                #create a new page object, add to set of page objects
                pageObj.add(Page(newPage, pageChildren))
    except AttributeError:
        print('{} has an attribute error.'.format(link))
        continue
  • Scrapy 会更适合我正在尝试做的事情吗?
  • 哪个库最适合显示连接?
  • 如何修复 getPages 函数以正确地将用户输入的 url 与从页面中提取的 href 结合起来?如果我在'https://en.wikipedia.org/wiki/Main_Page',我会得到'无法打开https://en.wikipedia.org/wiki/Main_Page/wiki/English_language'。我想我需要从 .org/ 的末尾合并并删除 /wiki/Main_Page 但我不知道最好的方法。

这是我的第一个真正的项目,所以任何关于如何改进我的逻辑的指针都非常感谢。

【问题讨论】:

    标签: python html web-scraping graph beautifulsoup


    【解决方案1】:

    这是第一个项目的好主意!

    Scrapy 会更适合我正在尝试做的事情吗?

    与您当前的版本相比,您的项目的 scrapy 版本有很多优势。您会立即感受到的优势是您提出请求的速度。但是,您可能需要一段时间才能适应 scrapy 项目的结构。

    如何修复 getPages 函数以正确地将用户输入的 url 与从页面中提取的 href 结合起来?如果我在'https://en.wikipedia.org/wiki/Main_Page',我会得到'无法打开https://en.wikipedia.org/wiki/Main_Page/wiki/English_language'。我想我需要从 .org/ 的末尾合并并删除 /wiki/Main_Page 但我不知道最好的方法。

    您可以使用urllib.parse.urljoin(startPage, relativeHref) 实现此目的。您将找到的大多数链接都是相对链接,然后您可以使用 urljoin 函数将其转换为绝对链接。
    在您的代码中,您可以将newPage = link.attrs['href'] 更改为newPage = urllib.parse.urljoin(startPage, link.attrs['href']) 并将page = urlopen('{}{}'.format(startPage, url)) 更改为page = urlopen(url)

    这里有几个示例,说明您可以在哪里稍微更改代码以获得一些好处。

    您可以使用 BeautifulSoup 的 find_all() 函数来代替 for link in BeautifulSoup(page, 'html.parser', parse_only=SoupStrainer('a')):,例如 for link in BeautifulSoup(page, 'html.parser').find_all('a', href=True):。这样,您的所有链接都已经保证有一个 href。

    为了防止同一页面上的链接出现两次,您应该将allLinks = []改为一个集合。

    这取决于偏好,但是从 Python 3.6 开始,还有另一种称为“f-Strings”的语法用于引用字符串中的变量。例如,您可以将print('{} has an attribute error.'.format(link)) 更改为print(f'{link} has an attribute error.')

    【讨论】:

      猜你喜欢
      • 2019-11-18
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-30
      • 2013-08-05
      • 1970-01-01
      相关资源
      最近更新 更多