教程:利用 Python 爬取网站的新手指南 | Linux 中国
优采云 发布时间: 2022-12-05 22:25教程:利用 Python 爬取网站的新手指南 | Linux 中国
关于合法性,访问大量有价值的信息可能令人兴奋,但仅仅因为它可能并不意味着应该这样做。
值得庆幸的是,有一些公共信息可以指导我们的道德准则和网络抓取工具。大多数 网站 都有一个与那个 网站 相关联的 robots.txt 文件,指示哪些爬行活动是允许的,哪些是不允许的。它主要用于与搜索引擎交互(网络抓取的最终形式)。但是,网站 上的大部分信息都被视为公共信息。出于这个原因,有些人将 robots.txt 文件视为一组建议,而不是具有法律约束力的文件。robots.txt 文件不涉及诸如合乎道德的数据采集和使用等主题。
在开始爬取项目之前,请问自己以下问题:
当我抓取 网站 时,请确保您可以对所有这些问题回答“否”。
要深入了解这些法律问题,请参阅 Krotov 和 Silva 撰写的网络抓取的合法性和道德规范以及 Sellars 撰写的二十年网络抓取和计算机欺诈和滥用法案,均于 2018 年出版。
现在开始爬行 网站
经过上面的评估,我想出了一个项目。我的目标是抓取爱达荷州所有 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() 将请求的页面转换为可读的内容,但还有其他输出类型:
我只使用拉丁字母对简单的英语 网站 进行操作。请求中的默认编码设置对此很有效。然而,除了简单的英语 网站 之外,还有更大的互联网世界。为确保请求正确解析内容,您可以设置文本的编码:
page = requests.get(URL)
page.encoding = 'ISO-885901'
soup = BeautifulSoup(page.text, 'html.parser')
仔细观察 BeautifulSoup 标签,我们看到:
确定如何获取内容
警告:此过程可能令人沮丧。
网站 抓取过程中的提取可能是一个充满陷阱的艰巨过程。我认为解决这个问题的最好方法是从一个有代表性的例子开始,然后扩展(这个原则适用于任何编程任务)。查看页面的 HTML 源代码至关重要。有很多方法可以做到这一点。
可以在终端使用Python查看页面的全部源码(不推荐)。运行此代码需要您自担风险:
print(soup.prettify())
虽然打印出页面的整个源代码可能适用于某些教程中显示的玩具示例,但大多数现代 网站 页面上都有很多东西。即使是 404 页面也可以填充页眉、页脚等代码。
通常,在您最喜欢的浏览器中通过“查看页面源代码”浏览源代码最简单(右键单击,然后选择“查看页面源代码”)。这是查找所需内容的最可靠方法(稍后我将解释原因)。
Family Dollar页面源代码
在这种情况下,我需要在这个巨大的 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_。soup.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
<p>
for i in city_hrefs[:2]:
print(i)
</p>
输出是用于抓取爱达荷州 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)
type(arco_json)
print(arco_json)
在该内容中,有一个名为 address 的键,它需要一个相对较小的嵌套字典中的地址信息。它可以像这样检索:
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)
我们做到了!Idaho Family Dollar 商店有一个逗号分隔的列表。多么激动人心。
关于 Selenium 和数据抓取的一些说明
Selenium 是一种用于自动与网页交互的常用工具。为了解释为什么它有时是必要的,让我们看一个使用 Walgreens 网站 的例子。“Inspect Element”提供浏览器显示内容的代码:
虽然“查看页面源代码”提供了有关将获得哪些请求的代码:
如果这两者不匹配,则有修改源代码的插件——因此应该在浏览器加载页面后访问它。requests 不能做到这一点,但 Selenium 可以。
Selenium 需要网络驱动程序来检索内容。实际上,它打开一个网络浏览器并采集该页面的内容。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)
作者注:本文改编自我于 2020 年 2 月 9 日在俄勒冈州波特兰的 PyCascades 上的演讲。
通过:
作者:Julia Piaskowski 题目:lujun9972 译者:stevenzdg988 校对:wxy
本文由LCTT原创编译,Linux中国荣幸推出
教程:站长工具网怎么样 站长工具网介绍
网站站长工具怎么样?当然很受欢迎!他可以说是一款非常流行的SEO工具。这在百度搜索引擎中对SEO关键词的排名就可以看出来。一个没有太多内容支持的简单工具页面就可以做SEO,关键词,百度搜索引擎搜索结果的自然排名。其次,可以看出 SEO 人员使用此工具的频率。
它还为我们的 SEO 流程带来了新想法,网站 最终的成功在于对用户有价值。下面杭州seo就为大家介绍一下站长工具,让我们看看它们为什么受到网站站长的青睐。
可以看出这个工具的使用非常简单,用户只需要输入网址查询,然后点击即可!
还提供丰富的数据和信息。查询主要包括:网站基本信息、百度相关、网站反链、历史收录、网站标题、关键词、描述信息、关键词排名信息、服务器信息等。
还有一个很实用的功能,长尾词推荐,系统会推荐一些可以根据我们的网站关键词优化的长尾关键词。在后续的优化中加入这些长尾关键词会大大增加网站的权重。
SEO站长工具可以根据需要对各种信息进行分类查询,可以查询到的信息比较完整、全面、准确度高。友情链接查询也比较完善。用户体验,速度和设计都不错,唯一就是广告太多。
但缺点并不能掩盖优点。这也是为什么有3000多种SEO工具,站长们却偏偏偏爱他的原因!哎~妈的,站长工具的魅力无处安放!