网站内容抓取工具(有人将robots.txt文件视为一组建议.py文件)

优采云 发布时间: 2021-11-04 17:22

  网站内容抓取工具(有人将robots.txt文件视为一组建议.py文件)

  关于合法性,获得大量有价值的信息可能令人兴奋,但仅仅因为它是可能的并不意味着应该这样做。

  幸运的是,有一些公共信息可以指导我们的道德和网络抓取工具。大多数网站都有一个与网站相关联的robots.txt文件,指明哪些爬行活动是允许的,哪些是不允许的。它主要用于与搜索引擎交互(网页抓取工具的终极形式)。但是,网站 上的大部分信息都被视为公开信息。因此,有些人将 robots.txt 文件视为一组建议,而不是具有法律约束力的文件。robots.txt 文件不涉及道德采集和数据使用等主题。

  在开始抓取项目之前,先问自己以下问题:

  当我抓取 网站 时,请确保您可以对所有这些问题回答“否”。

  要了解有关这些法律问题的更多信息,请参阅 Krotov 和 Silva 于 2018 年出版的“网络爬虫的合法性和道德”以及 Sellars 的“网络爬虫二十年和计算机欺诈和滥用法案”。

  现在开始爬取网站

  经过上面的评估,我想出了一个项目。我的目标是抓取爱达荷州所有 Family Dollar 商店的地址。这些店在农村很大,所以我想知道有多少这样的店。

  起点是Family Dollar的位置页面

  

  Family Dollar,爱达荷州位置页面

  首先,让我们在 Python 虚拟环境中加载先决条件。此处的代码将添加到 Python 文件(如果需要名称,则为 scraper.py)或在 JupyterLab 的单元格中运行。

  import requests # for making standard html requests

from bs4 import BeautifulSoup # magical tool for parsing html data

import json # for parsing data

from pandas import DataFrame as df # premier library for data organization

  接下来,我们从目标 URL 请求数据。

  page = requests.get("https://locations.familydollar.com/id/")

soup = BeautifulSoup(page.text, 'html.parser')

  BeautifulSoup 将 HTML 或 XML 内容转换为复杂的树对象。这些是我们将使用的几种常见对象类型。

  当我们查看 requests.get() 的输出时,还有更多问题需要考虑。我只使用 page.text() 将请求的页面转换为可读内容,但还有其他输出类型:

  我只对使用拉丁字母的纯英语 网站 进行操作。requests中的默认编码设置可以很好的解决这个问题。不过,除了纯英文的网站,就是更大的互联网世界。为确保请求正确解析内容,您可以设置文本的编码:

  page = requests.get(URL)

page.encoding = 'ISO-885901'

soup = BeautifulSoup(page.text, 'html.parser')

  仔细观察 BeautifulSoup 标签,我们看到:

  确定如何提取内容

  警告:此过程可能令人沮丧。

  网站 爬取过程中的提取可能是一个充满误解的艰巨过程。我认为解决这个问题最好的方法是从一个有代表性的例子开始,然后再扩展(这个原则适用于任何编程任务)。查看页面的 HTML 源代码很重要。有很多方法可以做到这一点。

  您可以在终端中使用 Python 来查看页面的整个源代码(不推荐)。运行此代码风险自负:

  print(soup.prettify())

  虽然打印页面的整个源代码可能适合一些教程中展示的玩具示例,但大多数现代 网站 页面都有很多内容。甚至 404 页面也可能充满了页眉、页脚和其他代码。

  通常,在您喜欢的浏览器中通过“查看页面源代码”来浏览源代码是最容易的(右键单击并选择“查看页面源代码”)。这是找到目标内容最可靠的方式(我稍后会解释原因)。

  

  家庭美元页面源代码

  在这种情况下,我需要在这个巨大的 HTML 海洋中找到我的目标内容地址、城市、州和邮政编码。通常,在页面源上进行简单的搜索(ctrl+F)就会得到目标位置的位置。一旦我真正看到目标内容的示例(至少是一家商店的地址),我就会找到将该内容与其他内容区分开来的属性或标签。

  首先,我需要在爱达荷州的Family Dollar商店采集不同城市的URL,并访问这些网站以获取地址信息。这些 URL 似乎收录在 href 标签中。奇妙!我将尝试使用 find_all 命令进行搜索:

  dollar_tree_list = soup.find_all('href')

dollar_tree_list

  搜索 href 不会产生任何结果,该死的。这可能会失败,因为 href 嵌套在 itemlist 类中。对于下一次尝试,搜索 item_list。由于 class 是 Python 中的保留字,因此使用 class_ 代替。sound.find_all() 原来是 bs4 函数的瑞士*敏*感*词*。

  dollar_tree_list = soup.find_all(class_ = 'itemlist')

for i in dollar_tree_list[:2]:

  print(i)

  有趣的是,我发现搜索特定类的方法通常是成功的方法。通过找出对象的类型和长度,我们可以了解更多关于对象的信息。

  type(dollar_tree_list)

len(dollar_tree_list)

  您可以使用 .contents 从 BeautifulSoup“结果集”中提取内容。这也是创建单个代表性示例的好时机。

  example = dollar_tree_list[2] # a representative example

example_content = example.contents

print(example_content)

  使用 .attr 查找对象内容中存在的属性。注意: .contents 通常会返回一个精确的项目列表,因此第一步是使用方括号表示法为项目建立索引。

  example_content = example.contents[0]

example_content.attrs

  现在,我可以看到 href 是一个属性,可以像字典项一样提取:

  example_href = example_content['href']

print(example_href)

  集成网站爬虫

  所有这些探索都为我们提供了前进的道路。这是一个清理版本,以澄清上述逻辑。

  city_hrefs = [] # initialise empty list

for i in dollar_tree_list:

    cont = i.contents[0]

    href = cont['href']

    city_hrefs.append(href)

#  check to be sure all went well

for i in city_hrefs[:2]:

  print(i)

  输出是用于抓取爱达荷州 Family Dollar 商店的 URL 列表。

  换句话说,我还没有得到地址信息!现在,您需要抓取每个城市的 URL 以获取此信息。因此,我们使用一个具有代表性的示例来重新启动该过程。

  page2 = requests.get(city_hrefs[2]) # again establish a representative example

soup2 = BeautifulSoup(page2.text, 'html.parser')

  

  家庭美元地图和代码

  地址信息嵌套在 type="application/ld+json" 中。经过大量的地理位置爬取,我开始意识到这是一个存储地址信息的通用结构。幸运的是,soup.find_all() 支持类型搜索。

  arco = soup2.find_all(type="application/ld+json")

print(arco[1])

  地址信息在第二个列表成员中!我懂了!

  使用 .contents 提取内容(从第二个列表项中)(这是过滤后合适的默认操作)。同样,由于输出是一个列表,我为列表项建立了一个索引:

  arco_contents = arco[1].contents[0]

arco_contents

  哦,看起来不错。此处提供的格式与 JSON 格式一致(并且,类型名称确实收录“json”)。JSON 对象的行为类似于带有嵌套字典的字典。一旦你熟悉了它,它实际上是一种很好的格式(当然,它比一长串正则表达式命令更容易编程)。虽然在结构上看起来像一个 JSON 对象,但它仍然是一个 bs4 对象,需要通过编程方式转换为 JSON 对象才能访问它:

  arco_json =  json.loads(arco_contents)

  在内容中,有一个被调用的地址键,它要求地址信息在一个相对较小的嵌套字典中。可以这样检索:

  arco_address = arco_json['address']

arco_address

  好的,请注意。现在我可以遍历存储的爱达荷州 URL 列表:

  locs_dict = [] # initialise empty list

for link in city_hrefs:

  locpage = requests.get(link)   # request page info

  locsoup = BeautifulSoup(locpage.text, 'html.parser')

      # parse the page's content

  locinfo = locsoup.find_all(type="application/ld+json")

      # extract specific element

  loccont = locinfo[1].contents[0]  

      # get contents from the bs4 element set

  locjson = json.loads(loccont)  # convert to json

  locaddr = locjson['address'] # get address

  locs_dict.append(locaddr) # add address to list

  使用 Pandas 来组织我们的 网站 爬取结果

  我们在字典中加载了大量数据,但是有一些额外的无用项使得重用数据变得比必要的复杂。为了执行最终的数据组织,我们需要将其转换为 Pandas 数据框,删除不必要的列@type 和 country,并检查前五行以确保一切正常。

  locs_df = df.from_records(locs_dict)

locs_df.drop(['@type', 'addressCountry'], axis = 1, inplace = True)

locs_df.head(n = 5)

  一定要保存结果!!

  df.to_csv(locs_df, "family_dollar_ID_locations.csv", sep = ",", index = False)

  我们做到了!爱达荷州的所有 Family Dollar 商店都有一个以逗号分隔的列表。多么激动人心。

  Selenium 和数据抓取的一点解释

  Selenium 是一种常用的工具,用于自动与网页交互。为了解释为什么有时需要使用它,让我们看一个使用 Walgreens 网站 的例子。“检查元素”提供浏览器显示内容的代码:

  

  尽管“查看页面源代码”提供了有关请求将获得什么的代码:

  

  如果这两个不一致,有插件可以修改源代码——因此,你应该在加载到浏览器后访问页面。requests 不能这样做,但 Selenium 可以。

  Selenium 需要一个 Web 驱动程序来检索内容。事实上,它会打开一个网络浏览器并采集这个页面的内容。Selenium 功能强大——它可以通过多种方式与加载的内容交互(请阅读文档)。使用Selenium获取数据后,继续像之前一样使用BeautifulSoup:

  url = "https://www.walgreens.com/storelistings/storesbycity.jsp?requestType=locator&state=ID"

driver = webdriver.Firefox(executable_path = 'mypath/geckodriver.exe')

driver.get(url)

soup_ID = BeautifulSoup(driver.page_source, 'html.parser')

store_link_soup = soup_ID.find_all(class_ = 'col-xl-4 col-lg-4 col-md-4')

  在 Family Dollar 的情况下,我不需要 Selenium,但是当呈现的内容与源代码不同时,我会继续使用 Selenium。

  概括

  总之,当使用网站爬行完成有意义的任务时:

  如果您对答案感到好奇:

  

  家庭美元位置图

  在美国有很多 Family Dollar 商店。

  完整的源代码是:

  import requests

from bs4 import BeautifulSoup

import json

from pandas import DataFrame as df

page = requests.get("https://www.familydollar.com/locations/")

soup = BeautifulSoup(page.text, 'html.parser')

# find all state links

state_list = soup.find_all(class_ = 'itemlist')

state_links = []

for i in state_list:

    cont = i.contents[0]

    attr = cont.attrs

    hrefs = attr['href']

    state_links.append(hrefs)

# find all city links

city_links = []

for link in state_links:

    page = requests.get(link)

    soup = BeautifulSoup(page.text, 'html.parser')

    familydollar_list = soup.find_all(class_ = 'itemlist')

    for store in familydollar_list:

        cont = store.contents[0]

        attr = cont.attrs

        city_hrefs = attr['href']

        city_links.append(city_hrefs)

# to get individual store links

store_links = []

for link in city_links:

    locpage = requests.get(link)

    locsoup = BeautifulSoup(locpage.text, 'html.parser')

    locinfo = locsoup.find_all(type="application/ld+json")

    for i in locinfo:

        loccont = i.contents[0]

        locjson = json.loads(loccont)

        try:

            store_url = locjson['url']

            store_links.append(store_url)

        except:

            pass

# get address and geolocation information

stores = []

for store in store_links:

    storepage = requests.get(store)

    storesoup = BeautifulSoup(storepage.text, 'html.parser')

    storeinfo = storesoup.find_all(type="application/ld+json")

    for i in storeinfo:

        storecont = i.contents[0]

        storejson = json.loads(storecont)

        try:

            store_addr = storejson['address']

            store_addr.update(storejson['geo'])

            stores.append(store_addr)

        except:

            pass

# final data parsing

stores_df = df.from_records(stores)

stores_df.drop(['@type', 'addressCountry'], axis = 1, inplace = True)

stores_df['Store'] = "Family Dollar"

df.to_csv(stores_df, "family_dollar_locations.csv", sep = ",", index = False)

  ① Python 电子书 2000 多本(主流经典书籍应有) ② Python 标准库资料(最全中文版) ③ 项目源代码(四十、五十个有趣经典的动手项目和源代码) ④ 简介转Python基础、爬虫、网页开发、大数据分析视频(适合小白学习)⑤Python学习路线图(告别无感学习)

  Python超全数据库安装包学习路线项目源码免费分享

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线