【问题标题】:Web crawler not able to process more than one webpage网络爬虫无法处理多个网页
【发布时间】:2018-06-19 13:15:53
【问题描述】:

我正在尝试使用以下程序从网页中提取有关 mtg 卡的一些信息,但我反复检索有关给定初始页面的信息 (InitUrl)。爬虫无法继续进行。我开始相信我没有使用正确的 url,或者使用 urllib 的限制可能会引起我的注意。这是我数周以来一直在努力的代码:

import re
from math import ceil
from urllib.request import urlopen as uReq, Request
from bs4 import BeautifulSoup as soup

InitUrl = "https://mtgsingles.gr/search?q=dragon"
NumOfCrawledPages = 0
URL_Next = ""
NumOfPages = 4   # depth of pages to be retrieved

query = InitUrl.split("?")[1]


for i in range(0, NumOfPages):
    if i == 0:
        Url = InitUrl
    else:
        Url = URL_Next

    print(Url)

    UClient = uReq(Url)  # downloading the url
    page_html = UClient.read()
    UClient.close()

    page_soup = soup(page_html, "html.parser")

    cards = page_soup.findAll("div", {"class": ["iso-item", "item-row-view"]})

    for card in cards:
        card_name = card.div.div.strong.span.contents[3].contents[0].replace("\xa0 ", "")

        if len(card.div.contents) > 3:
            cardP_T = card.div.contents[3].contents[1].text.replace("\n", "").strip()
        else:
            cardP_T = "Does not exist"

        cardType = card.contents[3].text
        print(card_name + "\n" + cardP_T + "\n" + cardType + "\n")

    try:
        URL_Next = InitUrl + "&page=" + str(i + 2)

        print("The next URL is: " + URL_Next + "\n")
    except IndexError:
        print("Crawling process completed! No more infomation to retrieve!")
    else:
        NumOfCrawledPages += 1
        Url = URL_Next
    finally:
        print("Moving to page : " + str(NumOfCrawledPages + 1) + "\n")

【问题讨论】:

  • 看看这个 - 关于 try except else 最终如何工作。 stackoverflow.com/a/31626974/8240959
  • 我做了,但我没有注意到关于 try-except-else-finally 语句的代码有什么问题。

标签: python beautifulsoup web-crawler urllib


【解决方案1】:

您的代码失败的原因之一是您没有使用 cookie。该网站似乎需要这些才能允许分页。

提取您感兴趣的数据的简洁方法如下:

import requests
from bs4 import BeautifulSoup

# the site actually uses this url under the hood for paging - check out Google Dev Tools
paging_url = "https://mtgsingles.gr/search?ajax=products-listing&lang=en&page={}&q=dragon"
return_list = []
# the page-scroll will only work when we support cookies
# so we fetch the page in a session
session = requests.Session()
session.get("https://mtgsingles.gr/")

除了最后一个之外,所有页面都有一个下一步按钮。所以我们使用这些知识循环直到下一个按钮消失。当它出现时——意味着到达最后一页——按钮被替换为“下一个隐藏”类的“li”标签。这仅存在于最后一页

现在我们准备开始循环

page = 1 # set count for start page
keep_paging = True # use flag to end loop when last page is reached
while keep_paging:
    print("[*] Extracting data for page {}".format(page))
    r = session.get(paging_url.format(page))
    soup = BeautifulSoup(r.text, "html.parser")
    items = soup.select('.iso-item.item-row-view.clearfix')
    for item in items:
        name = item.find('div', class_='col-md-10').get_text().strip().split('\xa0')[0]
        toughness_element = item.find('div', class_='card-power-toughness')
        try:
            toughness = toughness_element.get_text().strip()
        except:
            toughness = None
        cardtype = item.find('div', class_='cardtype').get_text()
        card_dict = {
            "name": name,
            "toughness": toughness,
            "cardtype": cardtype
        }
        return_list.append(card_dict)

    if soup.select('li.next.hidden'): # this element only exists if the last page is reached
        keep_paging = False
        print("[*] Scraper is done. Quitting...")
    else:
        page += 1

# do stuff with your list of dicts - e.g. load it into pandas and save it to a spreadsheet

这将滚动直到没有更多页面存在 - 无论站点中有多少子页面。

我在上面评论中的观点仅仅是,如果您在代码中遇到异常,您的页数将永远不会增加。这可能不是您想要做的,这就是为什么我建议您更多地了解整个 try-except-else-finally 交易的行为。

【讨论】:

  • 虽然有很多我没有完全理解的东西,但效果非常好。有没有什么好的资源可以学习更多关于网络抓取的信息,因为我有点不知所措......非常感谢!
  • O'Reiley 写了一本关于网页抓取的好书。看看那个 - shop.oreilly.com/product/0636920034391.do
  • 我知道这已经很长时间了,但我正在重新访问相同的代码。我想问一下您是如何找到该页面使用的真实网址(mtgsingles.gr/…{}&q=dragon)的。我使用 chrome 开发工具,我找到了网址:mtgsingles.gr/…
【解决方案2】:

我也被欺骗了,请求给出了相同的回复,忽略了页面参数。作为一个肮脏的解决方案,我可以首先为您提供将page-size 设置为足够高的数字以获取您想要的所有项目(此参数由于某种原因起作用......)

  import re
  from math import ceil
  import requests
  from bs4 import BeautifulSoup as soup

  InitUrl = Url = "https://mtgsingles.gr/search"
  NumOfCrawledPages = 0
  URL_Next = ""
  NumOfPages = 2   # depth of pages to be retrieved

  query = "dragon"
  cardSet=set()

  for i in range(1, NumOfPages):
      page_html = requests.get(InitUrl,params={"page":i,"q":query,"page-size":999})
      print(page_html.url)
      page_soup = soup(page_html.text, "html.parser")

      cards = page_soup.findAll("div", {"class": ["iso-item", "item-row-view"]})

      for card in cards:
          card_name = card.div.div.strong.span.contents[3].contents[0].replace("\xa0 ", "")

          if len(card.div.contents) > 3:
              cardP_T = card.div.contents[3].contents[1].text.replace("\n", "").strip()
          else:
              cardP_T = "Does not exist"

          cardType = card.contents[3].text
          cardString=card_name + "\n" + cardP_T + "\n" + cardType + "\n"
          cardSet.add(cardString)
          print(cardString)
      NumOfCrawledPages += 1
      print("Moving to page : " + str(NumOfCrawledPages + 1) + " with " +str(len(cards)) +"(cards)\n")

【讨论】:

  • 基本上在您的脚本中,我们不会逐页检索我们的信息,但“page-size”参数包括同一页面中的所有搜索结果。至少这是我能理解的。
  • 如果我们想让爬虫从一个页面移动到另一个页面怎么办?我怎样才能自己收缩下一个网址?
  • 此外,我相信在您的代码中不需要 for 循环。
  • 是的,是的,for 循环是不必要的,对吧。逐页解决方案在理论上与 Petris 实现它的方式完全一致。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多