數據是企業能夠擁有的最有價值的資產之一。它是數據科學和數據分析的核心:沒有數據,它們都是過時的。積極收集數據的企業可能比不收集數據的公司具有競爭優勢。有了足夠的數據,組織可以更好地確定問題的原因并做出明智的決定。
在某些情況下,組織可能缺乏足夠的數據來得出必要的見解。例如,初創企業幾乎總是在沒有數據的情況下開始。與其抱怨他們的不足,更好的解決方案是使用數據采集技術來幫助構建定制數據庫。
這篇文章介紹了一種流行的數據采集技術,稱為網絡抓取。您可以使用 kurtispykes/web-scraping-real-estate-data GitHub 存儲庫中的代碼進行后續操作。
什么是數據采集?
Data acquisition (也稱為 DAQ )可能與技術人員記錄烤箱溫度一樣簡單。您可以將 DAQ 定義為對測量真實世界物理現象的信號進行采樣,并將生成的樣本轉換為計算機可以解釋的數字數值的過程。
在一個理想的世界里,我們將把所有的數據都交給我們,隨時可以使用。然而,世界遠非理想。數據采集技術之所以存在,是因為某些問題需要特定的數據,而您在特定時間可能無法訪問這些數據。在進行任何數據分析之前,數據團隊必須有足夠的可用數據。一種獲取數據的技術是 web scraping 。
什么是網頁刮取?
Web 抓取是一種流行的數據采集技術,在那些對大數據需求不斷增長的人中,它已成為討論的熱門話題。從本質上講,這是一個從互聯網中提取信息并將其格式化以便于在數據分析和數據科學管道中使用的過程。
在過去,網頁抓取是一個手動過程。這個過程既乏味又耗時,而且人類容易出錯。最常見的解決方案是自動化。 web 刮取的自動化使您能夠加快流程,同時節省資金并減少人為錯誤的可能性。
然而,網絡抓取也有其挑戰。
刮網的挑戰
除了知道如何編程和理解 HTML 之外,構建自己的 web scraper 還有很多挑戰。提前了解數據收集過程中可能遇到的各種障礙是有益的。以下是從 web 上抓取數據時面臨的一些最常見的挑戰。
robots.txt
抓取數據的權限通常保存在 robots.txt 文件中。此文件用于通知爬網程序可在網站上訪問的 URL 。它可以防止站點被請求過載。
在開始網頁抓取項目之前,首先要檢查的是目標網站是否允許網頁抓取。網站可以決定是否允許在其網站上使用刮片器進行刮片。
有些網站不允許自動抓取網頁,這通常是為了防止競爭對手獲得競爭優勢,并從目標站點中耗盡服務器資源。它確實會影響網站的性能。
您可以通過將 /robots.txt 附加到域名來檢查網站的 robots.txt 文件。例如,檢查 Twitter 的 robots.txt 如下: www.twitter.com/robots.txt 。
結構變化
UI 和 UX 開發人員定期對網站進行添加、刪除和定期結構更改,以使其跟上最新進展。 Web scraper 依賴于構建 scraper 時網頁的代碼元素。因此,頻繁更改網站可能會導致數據丟失。隨時關注網頁的更改總是一個好主意。
此外,考慮到不同的網頁設計者在設計網頁時可能有不同的標準。這意味著,如果你計劃抓取多個網站,你可能需要構建多個抓取器,每個網站一個。
IP 攔截器,或被禁止
它有可能被禁止進入網站。如果你的網絡爬蟲向某個網站發送的請求數量非常高,那么你的 IP 地址可能會被禁止。或者,網站可能會限制其訪問,以打破刮取過程。
在被認為是道德的和不道德的網絡抓取之間有一條細線:越過這條線很快就會導致 IP 屏蔽。
驗證碼
CAPTCHA (完全自動化的公共圖靈測試,以區分計算機和人類)正是它的名字所說的:區分人類和機器人。驗證碼所帶來的問題對于人類來說通常是合乎邏輯的、簡單明了的,但對于機器人來說,要完成同樣的任務是很有挑戰性的,這可以防止網站被垃圾郵件攻擊。
使用 CAPTCHA 抓取網站有一些合乎道德的解決方法。然而,這一討論超出了本文的范圍。
蜜罐陷阱
類似于你如何設置設備或外殼來捕捉入侵你家的害蟲,網站所有者設置蜜罐陷阱來捕捉刮器。這些陷阱通常是人類看不到的鏈接,但對網絡爬蟲來說是可見的。
其目的是獲取有關刮板的信息,例如其 IP 地址,以便他們阻止刮板訪問網站。
實時數據抓取
在某些情況下,您可能需要實時丟棄數據(例如,價格比較)。由于更改隨時可能發生,因此刮取器必須不斷監控網站并刮取數據。實時獲取大量數據具有挑戰性。
Web 抓取最佳實踐
現在,您已經意識到可能面臨的挑戰,了解最佳實踐以確保您在道德上收集網絡數據非常重要。
尊重 robots.txt
在抓取 web 數據時,您將面臨的一個挑戰是遵守 robots.txt 的條款。遵循網站設置的關于 web 抓取可以抓取和不能抓取的指南是最佳做法。
如果一個網站不允許網絡抓取,那么抓取該網站是不道德的。最好找到另一個數據源,或者直接聯系網站所有者,討論解決方案。
善待服務器
Web 服務器只能承受這么多。超過 web 服務器的負載會導致服務器崩潰。考慮向主機服務器發出請求的可接受頻率。短時間內的幾個請求可能會導致服務器故障,進而破壞網站其他訪問者的用戶體驗。
保持請求之間的合理時間間隔,并考慮并行請求的數量。
非高峰時段刮水
了解一個網站什么時候可能會收到最多的流量,并避免在這段時間內進行抓取。您的目標是不妨礙其他訪問者的用戶體驗。當一個網站收到的流量減少時,你的道德責任是刮一刮。(這也對您有利,因為它顯著提高了刮板的速度。)
剪貼畫教程
Python 中的 Web 抓取通常涉及從零開始編寫幾個低級任務。然而, Scrapy ,一個開源的網絡爬行框架,默認情況下處理幾個常見的啟動需求。這意味著您可以專注于從目標網站中提取所需的數據。
為了展示 Scrapy 的威力,您開發了一個 spider ,這是一個 Scrapy 類,您可以在其中定義刮網器的行為。使用這個蜘蛛從 Boston Realty Advisors 網站上抓取所有列表。
在開始任何 web 刮取項目之前,檢查目標網站以進行刮取非常重要。在檢查網站時,我喜歡檢查的第一件事是頁面是靜態的還是由 JavaScript 生成的。
要打開開發人員工具箱,請按 F12 。在 Network 選項卡上,確保選中 Disable cache 。
要打開命令選項板,請按 CTRL + SHIFT + P ( Windows Linux )或 command + SHIFT-P ( Mac )。鍵入 Disable JavaScript ,然后按 Enter 鍵并重新加載目標網站。
空頁面告訴您目標網頁是使用 JavaScript 生成的。您無法通過解析開發者工具箱 Elements 選項卡中顯示的 HTML 元素來抓取頁面。在開發人員工具中重新啟用 JavaScript 并重新加載頁面。
還有更多要檢查的。
I 在開發人員工具箱中,選擇 XHR ( XMLHTTPRequest )選項卡。瀏覽發送到服務器的請求后,我注意到一些有趣的事情。有兩個請求稱為“ inventory ”,但在一個請求中,您可以訪問 JSON 中第一頁上的所有數據。
這一信息非常有用,因為這意味著您不必訪問波士頓房地產顧問網站上的主列表頁面即可獲取所需的數據。
現在你可以開始刮了。(我做了更多的檢查,以更好地理解如何模擬向服務器發出的請求,但這超出了本文的范圍。)
創建報廢項目
要設置 Scrapy 項目,首先安裝scrapy。我建議在 virtual environment 中執行此步驟。
pip install scrapy
激活虛擬環境后,輸入以下命令:
scrapy startproject bradvisors
該命令創建一個名為bradvisors的 Scrapy 項目。 Scrapy 還會自動將一些文件添加到目錄中。
運行命令后,最終目錄結構如下所示:
. └── bradvisors ├── bradvisors │ ├── __init__.py │ ├── items.py │ ├── middlewares.py │ ├── pipelines.py │ ├── settings.py │ └── spiders │ └── __init__.py └── scrapy.cfg
到目前為止,您已經檢查了網站的元素,并創建了 Scrapy 項目。
構建蜘蛛
蜘蛛模塊必須構建在bradvisors/bradvisors/spiders目錄中。我的蜘蛛腳本的名稱是bradvisors_spider.py,但您可以使用自定義名稱。
以下代碼從該網站中提取數據。代碼示例僅在items.py文件更新時成功運行。有關詳細信息,請參閱示例后的說明。
import json import scrapy from bradvisors.items import BradvisorsItem class BradvisorsSpider(scrapy.Spider): name = "bradvisors" start_urls = ["https://bradvisors.com/listings/"] url = "https://buildout.com/plugins/5339d012fdb9c122b1ab2f0ed59a55ac0327fd5f/inventory" headers = { 'authority': 'buildout.com', 'accept': 'application/json, text/javascript, */*; q=0.01', 'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8', 'cache-control': 'no-cache', 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'origin': 'https://buildout.com', 'pragma': 'no-cache', 'referer': 'https://buildout.com/plugins/5339d012fdb9c122b1ab2f0ed59a55ac0327fd5f/bradvisors.com/inventory/?pluginId=0&iframe=true&embedded=true&cacheSearch=true&=undefined', 'sec-ch-ua': '"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36', 'x-newrelic-id': 'Vg4GU1RRGwIJUVJUAwY=', 'x-requested-with': 'XMLHttpRequest' } def parse(self, response): url = "https://buildout.com/plugins/5339d012fdb9c122b1ab2f0ed59a55ac0327fd5f/inventory" # There are 5 pages on the website for i in range(5): # Change the page number in the payload payload = f"utf8=%E2%9C%93&polygon_geojson=&lat_min=&lat_max=&lng_min=&lng_max=&mobile_lat_min= &mobile_lat_max=&mobile_lng_min=&mobile_lng_max=&page={str(i)}&map_display_limit=500&map_type=roadmap &custom_map_marker_url=%2F%2Fs3.amazonaws.com%2Fbuildout-production%2Fbrandings%2F7242%2Fprofile_photo %2Fsmall.png%3F1607371909&use_marker_clusterer=true&placesAutoComplete=&q%5Btype_use_offset_eq_any%5D%5B%5D= &q%5Bsale_or_lease_eq%5D=&q%5Bbuilding_size_sf_gteq%5D=&q%5Bbuilding_size_sf_lteq%5D=&q%5B listings_data_max_space_available_on_market_gteq%5D=&q%5Blistings_data_min_space_available_on_market_lteq %5D=&q%5Bproperty_research_property_year_built_gteq%5D=&q%5Bproperty_research_property_year_built_lteq %5D=&q%5Bproperty_use_id_eq_any%5D%5B%5D=&q%5Bcompany_office_id_eq_any%5D%5B%5D=&q%5Bs%5D%5B%5D=" # Crawl the data, given the payload yield scrapy.Request(method="POST", body=payload, url=url, headers=self.headers, callback=self.parse_api) def parse_api(self, response): # Response is json, use loads to convert it into Python dictionary data = json.loads(response.body) # Our item object defined in items.py item = BradvisorsItem() for listing in data["inventory"]: item["address"] = listing["address_one_line"] item["city"] = listing["city"] item["city_state"] = listing["city_state"] item["zip"] = listing["zip"] item["description"] = listing["description"] item["size_summary"] = listing["size_summary"] item["item_url"] = listing["show_link"] item["property_sub_type_name"] = listing["property_sub_type_name"] item["sale"] = listing["sale"] item["sublease"] = listing["sublease"] yield item
該代碼完成以下任務:
將刮刀的名稱定義為bradvisors。
定義隨請求傳遞的標頭。
指定parse方法是刮板運行時的自動回調。
定義parse方法,在該方法中,您遍歷要抓取的頁數,將頁碼傳遞給有效負載,并生成該請求。這會在每次迭代時調用parse_api方法。
定義parse_api方法并將有效的 JSON 響應轉換為 Python 字典。
在items.py中定義BradvisorsItem類(下一個代碼示例)。
循環遍歷庫存中的所有列表并抓取特定元素。
# items.py import scrapy class BradvisorsItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() address = scrapy.Field() city = scrapy.Field() city_state = scrapy.Field() zip = scrapy.Field() description = scrapy.Field() size_summary = scrapy.Field() item_url = scrapy.Field() property_sub_type_name = scrapy.Field() sale = scrapy.Field()
接下來,必須執行刮取以解析數據。
運行鏟運機
從命令行導航到項目的根目錄(在本例中為bradvisors)。運行以下命令:
scrapy crawl bradvisors -o data.csv
該命令將抓取 Boston Realty Advisors 網站,并將提取的數據保存在項目根目錄的data.csv文件中。
太好了,您現在已經獲得了房地產數據!
接下來是什么?
隨著對大數據需求的增長,讓自己具備使用網絡抓取工具獲取數據的能力是一項非常有價值的技能。從互聯網上刪除數據可能會帶來一些挑戰。除了獲取所需的數據外,您的目標還應該是尊重網站,并以道德的方式收集網站。
-
NVIDIA
+關注
關注
14文章
4936瀏覽量
102813 -
AI
+關注
關注
87文章
30122瀏覽量
268407
發布評論請先 登錄
相關推薦
評論