成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

利用 Python 爬取網站的新手指南

開發 后端
這篇文章旨在說明如何使用 Python 的 requests 庫訪問網頁內容,并使用 BeatifulSoup4 庫以及 JSON 和 pandas 庫解析網頁內容。我將簡要介紹 Selenium 庫,但我不會深入研究如何使用該庫——這個主題值得有自己的教程。

通過基本的 Python 工具獲得爬取完整 HTML 網站的實踐經驗。

有很多很棒的書可以幫助你學習 Python ,但是誰真正讀了這那些大部頭呢?(劇透:反正不是我)。

許多人覺得教學書籍很有用,但我通常不會從頭到尾地閱讀一本書來學習。我是通過做一個項目,努力的弄清楚一些內容,然后再讀另一本書來學習。因此,暫時丟掉書,讓我們一起學習 Python。

接下來是我的第一個 Python 爬取項目的指南。它對 Python 和 HTML 的假定知識要求很低。這篇文章旨在說明如何使用 Python 的 requests 庫訪問網頁內容,并使用 BeatifulSoup4 庫以及 JSON 和 pandas 庫解析網頁內容。我將簡要介紹 Selenium 庫,但我不會深入研究如何使用該庫——這個主題值得有自己的教程。最終,我希望向你展示一些技巧和小竅門,以減少網頁爬取過程中遇到的問題。

安裝依賴

我的 GitHub 存儲庫 中提供了本指南的所有資源。如果需要安裝 Python3 的幫助,請查看 Linux、Windows 和 Mac 的教程。

  1. $ python3 -m venv
  2. $ source venv/bin/activate
  3. $ pip install requests bs4 pandas

如果你喜歡使用 JupyterLab ,則可以使用 notebook 運行所有代碼。安裝 JupyterLab 有很多方法,這是其中一種:

  1. # from the same virtual environment as above, run:
  2. $ pip install jupyterlab

為網站抓取項目設定目標

現在我們已經安裝了依賴項,但是爬取網頁需要做什么?

讓我們退一步,確保使目標清晰。下面是成功完成網頁爬取項目需求列表:

  • 我們收集的信息,是值得我們花大力氣去建立一個有效的網頁爬取器的。
  • 我們所下載的信息是可以通過網頁爬取器合法和道德地收集的。
  • 對如何在 HTML 代碼中找到目標信息有一定的了解。
  • 利用恰當的工具:在此情況下,需要使用 BeautifulSoup 庫和 requests 庫。
  • 知道(或愿意去學習)如何解析 JSON 對象。
  • 有足夠的 pandas 數據處理技能。

關于 HTML 的備注:HTML 是運行在互聯網上的“猛獸”,但我們最需要了解的是標簽的工作方式。標簽是一對由尖括號包圍關鍵詞(一般成對出現,其內容在兩個標簽中間)。比如,這是一個假裝的標簽,稱為 pro-tip

  1. <pro-tip> All you need to know about html is how tags work </pro-tip>

我們可以通過調用標簽 pro-tip 來訪問其中的信息(All you need to know…)。本教程將進一步介紹如何查找和訪問標簽。要進一步了解 HTML 基礎知識,請查看 本文。

網站爬取項目中要找的是什么

有些數據利用網站爬取采集比利用其他方法更合適。以下是我認為合適項目的準則:

沒有可用于數據(處理)的公共 API。通過 API 抓取結構化數據會容易得多,(所以沒有 API )有助于澄清收集數據的合法性和道德性。而有相當數量的結構化數據,并有規律的、可重復的格式,才能證明這種努力的合理性。網頁爬取可能會很痛苦。BeautifulSoup(bs4)使操作更容易,但無法避免網站的個別特殊性,需要進行定制。數據的相同格式化不是必須的,但這確實使事情變得更容易。存在的 “邊際案例”(偏離規范)越多,爬取就越復雜。

免責聲明:我沒有參加過法律培訓;以下內容無意作為正式的法律建議。

關于合法性,訪問大量有價值信息可能令人興奮,但僅僅因為它是可能的,并不意味著應該這樣做。

值得慶幸的是,有一些公共信息可以指導我們的道德規范和網頁爬取工具。大多數網站都有與該網站關聯的 robots.txt 文件,指出允許哪些爬取活動,哪些不被允許。它主要用于與搜索引擎(網頁抓取工具的終極形態)進行交互。然而,網站上的許多信息都被視為公共信息。因此,有人將 robots.txt 文件視為一組建議,而不是具有法律約束力的文檔。 robots.txt 文件并不涉及數據的道德收集和使用等主題。

在開始爬取項目之前,問自己以下問題:

  • 我是否在爬取版權材料?
  • 我的爬取活動會危害個人隱私嗎?
  • 我是否發送了大量可能會使服務器超載或損壞的請求?
  • 爬取是否會泄露出我不擁有的知識產權?
  • 是否有規范網站使用的服務條款,我是否遵循了這些條款?
  • 我的爬取活動會減少原始數據的價值嗎?(例如,我是否打算按原樣重新打包數據,或者可能從原始來源中抽取網站流量)?

當我爬取一個網站時,請確??梢詫λ羞@些問題回答 “否”。

要深入了解這些法律問題,請參閱 2018 年出版的 Krotov 和 Silva 撰寫的《Web 爬取的合法性和道德性》 和 Sellars 的《二十年 Web 爬取和計算機欺詐與濫用法案》。

現在開始爬取網站

經過上述評估,我想出了一個項目。我的目標是爬取愛達荷州所有 Family Dollar 商店的地址。 這些商店在農村地區規模很大,因此我想了解有多少家這樣的商店。

起點是 Family Dollar 的位置頁面

 

愛達荷州 Family Dollar 所在地頁面

首先,讓我們在 Python 虛擬環境中加載先決條件。此處的代碼將被添加到一個 Python 文件(如果你想要個名稱,則為 scraper.py)或在 JupyterLab 的單元格中運行。

  1. import requests # for making standard html requests
  2. from bs4 import BeautifulSoup # magical tool for parsing html data
  3. import json # for parsing data
  4. from pandas import DataFrame as df # premier library for data organization

接下來,我們從目標 URL 中請求數據。

  1. page = requests.get("https://locations.familydollar.com/id/")
  2. soup = BeautifulSoup(page.text, 'html.parser')

BeautifulSoup 將 HTML 或 XML 內容轉換為復雜樹對象。這是我們將使用的幾種常見對象類型。

  • BeautifulSoup —— 解析的內容
  • Tag —— 標準 HTML 標記,這是你將遇到的 bs4 元素的主要類型
  • NavigableString —— 標簽內的文本字符串
  • Comment —— NavigableString 的一種特殊類型

當我們查看 requests.get() 輸出時,還有更多要考慮的問題。我僅使用 page.text() 將請求的頁面轉換為可讀的內容,但是還有其他輸出類型:

  • page.text() 文本(最常見)
  • page.content() 逐字節輸出
  • page.json() JSON 對象
  • page.raw() 原始套接字響應(對你沒啥用)

我只在使用拉丁字母的純英語網站上操作。 requests 中的默認編碼設置可以很好地解決這一問題。然而,除了純英語網站之外,就是更大的互聯網世界。為了確保 requests 正確解析內容,你可以設置文本的編碼:

  1. page = requests.get(URL)
  2. page.encoding = 'ISO-885901'
  3. soup = BeautifulSoup(page.text, 'html.parser')

仔細研究 BeautifulSoup 標簽,我們看到:

  • bs4 元素 tag 捕獲的是一個 HTML 標記。
  • 它具有名稱和屬性,可以像字典一樣訪問:tag['someAttribute']。
  • 如果標簽具有相同名稱的多個屬性,則僅訪問第一個實例。
  • 可通過 tag.contents 訪問子標簽。
  • 所有標簽后代都可以通過 tag.contents 訪問。
  • 你始終可以使用以下字符串:re.compile("your_string") 訪問一個字符串的所有內容,而不是瀏覽 HTML 樹。

確定如何提取相應內容

警告:此過程可能令人沮喪。

網站爬取過程中的提取可能是一個令人生畏的充滿了誤區的過程。我認為解決此問題的最佳方法是從一個有代表性的示例開始然后進行擴展(此原理對于任何編程任務都是適用的)。查看頁面的 HTML 源代碼至關重要。有很多方法可以做到這一點。

你可以在終端中使用 Python 查看頁面的整個源代碼(不建議使用)。運行此代碼需要你自擔風險:

  1. print(soup.prettify())

雖然打印出頁面的整個源代碼可能適用于某些教程中顯示的玩具示例,但大多數現代網站的頁面上都有大量內容。甚至 404 頁面也可能充滿了頁眉、頁腳等代碼。

通常,在你喜歡的瀏覽器中通過 “查看頁面源代碼” 來瀏覽源代碼是最容易的(單擊右鍵,然后選擇 “查看頁面源代碼” )。這是找到目標內容的最可靠方法(稍后我將解釋原因)。

 

Family Dollar 頁面源代碼

在這種情況下,我需要在這個巨大的 HTML 海洋中找到我的目標內容 —— 地址、城市、州和郵政編碼。通常,對頁面源(ctrl+F)的簡單搜索就會得到目標位置所在的位置。一旦我實際看到目標內容的示例(至少一個商店的地址),便會找到將該內容與其他內容區分開的屬性或標簽。

首先,我需要在愛達荷州 Family Dollar 商店中收集不同城市的網址,并訪問這些網站以獲取地址信息。這些網址似乎都包含在 href 標記中。太棒了!我將嘗試使用 find_all 命令進行搜索:

  1. dollar_tree_list = soup.find_all('href')
  2. dollar_tree_list

搜索 href 不會產生任何結果,該死。這可能是因為 href 嵌套在 itemlist 類中而失敗。對于下一次嘗試,請搜索 item_list。由于 class 是 Python 中的保留字,因此使用 class_ 來作為替代。soup.find_all() 原來是 bs4 函數的瑞士軍刀。

  1. dollar_tree_list = soup.find_all(class_ = 'itemlist')
  2. for i in dollar_tree_list[:2]:
  3.   print(i)

有趣的是,我發現搜索一個特定類的方法一般是一種成功的方法。通過找出對象的類型和長度,我們可以了解更多有關對象的信息。

  1. type(dollar_tree_list)
  2. len(dollar_tree_list)

可以使用 .contents 從 BeautifulSoup “結果集” 中提取內容。這也是創建單個代表性示例的好時機。

  1. example = dollar_tree_list[2] # a representative example
  2. example_content = example.contents
  3. print(example_content)

使用 .attr 查找該對象內容中存在的屬性。注意:.contents 通常會返回一個項目的精確的列表,因此第一步是使用方括號符號為該項目建立索引。

  1. example_content = example.contents[0]
  2. example_content.attrs

現在,我可以看到 href 是一個屬性,可以像字典項一樣提取它:

  1. example_href = example_content['href']
  2. print(example_href)

整合網站抓取工具

所有的這些探索為我們提供了前進的路徑。這是厘清上面邏輯的一個清理版本。

  1. city_hrefs = [] # initialise empty list
  2.  
  3. for i in dollar_tree_list:
  4.     cont = i.contents[0]
  5.     href = cont['href']
  6.     city_hrefs.append(href)
  7.  
  8. #  check to be sure all went well
  9. for i in city_hrefs[:2]:
  10.   print(i)

輸出的內容是一個關于抓取愛達荷州 Family Dollar 商店 URL 的列表。

也就是說,我仍然沒有獲得地址信息!現在,需要抓取每個城市的 URL 以獲得此信息。因此,我們使用一個具有代表性的示例重新開始該過程。

  1. page2 = requests.get(city_hrefs[2]) # again establish a representative example
  2. soup2 = BeautifulSoup(page2.text, 'html.parser')

 

Family Dollar 地圖和代碼

地址信息嵌套在 type="application/ld+json" 里。經過大量的地理位置抓取之后,我開始認識到這是用于存儲地址信息的一般結構。幸運的是,soup.find_all() 開啟了利用 type 搜索。

  1. arco = soup2.find_all(type="application/ld+json")
  2. print(arco[1])

地址信息在第二個列表成員中!原來如此!

使用 .contents 提?。◤牡诙€列表項中)內容(這是過濾后的合適的默認操作)。同樣,由于輸出的內容是一個列表,因此我為該列表項建立了索引:

  1. arco_contents = arco[1].contents[0]
  2. arco_contents

喔,看起來不錯。此處提供的格式與 JSON 格式一致(而且,該類型的名稱中確實包含 “json”)。 JSON 對象的行為就像是帶有嵌套字典的字典。一旦你熟悉利用其去工作,它實際上是一種不錯的格式(當然,它比一長串正則表達式命令更容易編程)。盡管從結構上看起來像一個 JSON 對象,但它仍然是 bs4 對象,需要通過編程方式轉換為 JSON 對象才能對其進行訪問:

  1. arco_json =  json.loads(arco_contents)
  1. type(arco_json)
  2. print(arco_json)

在該內容中,有一個被調用的 address 鍵,該鍵要求地址信息在一個比較小的嵌套字典里。可以這樣檢索:

  1. arco_address = arco_json['address']
  2. arco_address

好吧,請大家注意。現在我可以遍歷存儲愛達荷州 URL 的列表:

  1. locs_dict = [] # initialise empty list
  2.  
  3. for link in city_hrefs:
  4.   locpage = requests.get(link)   # request page info
  5.   locsoup = BeautifulSoup(locpage.text, 'html.parser')
  6.       # parse the page's content
  7.   locinfo = locsoup.find_all(type="application/ld+json")
  8.       # extract specific element
  9.   loccont = locinfo[1].contents[0]  
  10.       # get contents from the bs4 element set
  11.   locjson = json.loads(loccont)  # convert to json
  12.   locaddr = locjson['address'] # get address
  13.   locs_dict.append(locaddr) # add address to list

用 Pandas 整理我們的網站抓取結果

我們在字典中裝載了大量數據,但是還有一些額外的無用項,它們會使重用數據變得比需要的更為復雜。要執行最終的數據組織,我們需要將其轉換為 Pandas 數據框架,刪除不需要的列 @type 和 country,并檢查前五行以確保一切正常。

  1. locs_df = df.from_records(locs_dict)
  2. locs_df.drop(['@type', 'addressCountry'], axis = 1, inplace = True)
  3. locs_df.head(n = 5)

確保保存結果?。?/p>

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

我們做到了!所有愛達荷州 Family Dollar 商店都有一個用逗號分隔的列表。多令人興奮。

Selenium 和數據抓取的一點說明

Selenium 是用于與網頁自動交互的常用工具。為了解釋為什么有時必須使用它,讓我們來看一個使用 Walgreens 網站的示例。 “檢查元素” 提供了瀏覽器顯示內容的代碼:

 

Walgreens 位置頁面和代碼

雖然 “查看頁面源代碼” 提供了有關 requests 將獲得什么內容的代碼:

 

Walgreens 源代碼

如果這兩個不一致,是有一些插件可以修改源代碼 —— 因此,應在將頁面加載到瀏覽器后對其進行訪問。requests 不能做到這一點,但是 Selenium 可以做到。

Selenium 需要 Web 驅動程序來檢索內容。實際上,它會打開 Web 瀏覽器,并收集此頁面的內容。Selenium 功能強大 —— 它可以通過多種方式與加載的內容進行交互(請閱讀文檔)。使用 Selenium 獲取數據后,繼續像以前一樣使用 BeautifulSoup:

  1. url = "https://www.walgreens.com/storelistings/storesbycity.jsp?requestType=locator&state=ID"
  2. driver = webdriver.Firefox(executable_path = 'mypath/geckodriver.exe')
  3. driver.get(url)
  4. soup_ID = BeautifulSoup(driver.page_source, 'html.parser')
  5. store_link_soup = soup_ID.find_all(class_ = 'col-xl-4 col-lg-4 col-md-4')

對于 Family Dollar 這種情形,我不需要 Selenium,但是當呈現的內容與源代碼不同時,我確實會保留使用 Selenium。

小結

總之,使用網站抓取來完成有意義的任務時:

  • 耐心一點
  • 查閱手冊(它們非常有幫助)

如果你對答案感到好奇:

 

Family Dollar 位置圖

美國有很多 Family Dollar 商店。

完整的源代碼是:

  1. import requests
  2. from bs4 import BeautifulSoup
  3. import json
  4. from pandas import DataFrame as df
  5.  
  6. page = requests.get("https://www.familydollar.com/locations/")
  7. soup = BeautifulSoup(page.text, 'html.parser')
  8.  
  9. # find all state links
  10. state_list = soup.find_all(class_ = 'itemlist')
  11.  
  12. state_links = []
  13.  
  14. for i in state_list:
  15. cont = i.contents[0]
  16. attr = cont.attrs
  17. hrefs = attr['href']
  18. state_links.append(hrefs)
  19.  
  20. # find all city links
  21. city_links = []
  22.  
  23. for link in state_links:
  24. page = requests.get(link)
  25. soup = BeautifulSoup(page.text, 'html.parser')
  26. familydollar_list = soup.find_all(class_ = 'itemlist')
  27. for store in familydollar_list:
  28. cont = store.contents[0]
  29. attr = cont.attrs
  30. city_hrefs = attr['href']
  31. city_links.append(city_hrefs)
  32. # to get individual store links
  33. store_links = []
  34.  
  35. for link in city_links:
  36. locpage = requests.get(link)
  37. locsoup = BeautifulSoup(locpage.text, 'html.parser')
  38. locinfo = locsoup.find_all(type="application/ld+json")
  39. for i in locinfo:
  40. loccont = i.contents[0]
  41. locjson = json.loads(loccont)
  42. try:
  43. store_url = locjson['url']
  44. store_links.append(store_url)
  45. except:
  46. pass
  47.  
  48. # get address and geolocation information
  49. stores = []
  50.  
  51. for store in store_links:
  52. storepage = requests.get(store)
  53. storesoup = BeautifulSoup(storepage.text, 'html.parser')
  54. storeinfo = storesoup.find_all(type="application/ld+json")
  55. for i in storeinfo:
  56. storecont = i.contents[0]
  57. storejson = json.loads(storecont)
  58. try:
  59. store_addr = storejson['address']
  60. store_addr.update(storejson['geo'])
  61. stores.append(store_addr)
  62. except:
  63. pass
  64.  
  65. # final data parsing
  66. stores_df = df.from_records(stores)
  67. stores_df.drop(['@type', 'addressCountry'], axis = 1, inplace = True)
  68. stores_df['Store'] = "Family Dollar"
  69.  
  70. df.to_csv(stores_df, "family_dollar_locations.csv", sep = ",", index = False)

 

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2022-05-16 15:37:32

開源軟件

2010-06-07 16:10:53

HadoopOnDem

2022-04-08 12:56:52

Linux終端命令

2025-01-13 07:15:00

Monorepo代碼倉庫中項目代碼管理

2021-03-18 09:18:12

python爬蟲

2010-06-21 12:39:56

OSPF路由協議

2023-03-01 08:00:00

機器學習數據集

2010-05-27 10:42:38

SVN配置文檔

2009-11-16 08:58:43

PHP語言

2011-03-30 14:07:56

Ubuntu的安裝

2011-05-13 08:56:46

搜索引擎sitemap

2011-08-23 10:11:10

LinuxTop命令

2010-08-04 09:06:21

Flex安裝

2021-12-30 10:26:37

Bash Shell腳本文件命令

2023-03-15 09:46:07

R Markdown代碼語法

2022-02-28 11:02:53

函數Bash Shell語句

2022-01-20 16:43:38

Bash 腳本ShellLinux

2010-05-17 11:24:33

2010-09-01 16:56:11

無線局域網

2010-07-01 12:35:46

UML用例圖
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区精品电影 | 国产免费一区二区三区 | 国产精品久久精品 | 天天爱天天操 | 亚洲精品一区二区在线观看 | av中文字幕在线 | 国产高清精品在线 | 国产精品美女久久久久久不卡 | 国产激情在线看 | 看特级黄色片 | 99视频在线 | 99精品欧美一区二区三区综合在线 | 91精品国产一区二区三区动漫 | 一区二区精品视频 | 国产精品二区三区 | 欧美一级艳情片免费观看 | 中文字幕亚洲一区二区三区 | 久久青青 | 亚洲久在线 | 欧美日韩在线一区二区三区 | 欧美激情精品久久久久 | 91亚洲精品在线 | 亚洲国产欧美在线人成 | 国产欧美久久一区二区三区 | 欧美一级片黄色 | 精品国产欧美 | 精品伊人 | 久久99精品久久久久久国产越南 | 午夜资源 | 国产日韩欧美一区二区 | 国产高清一区二区 | 91中文在线观看 | 国产婷婷精品av在线 | 少妇久久久| 精品久久久久久久人人人人传媒 | 日韩精品在线看 | 日韩欧美不卡 | 羞羞视频网站免费观看 | 精品一区av| 国产99久久精品一区二区永久免费 | 91极品尤物在线播放国产 |