- 來源 | 願碼(ChainDesk.CN)內容編輯
- 願碼Slogan | 鏈接每一個程序員的故事
- 網站 | http://chaindesk.cn
- 願碼願景 | 打造全學科IT系統免費課程,助力小白用戶、初級工程師0成本免費系統學習、低成本進階,幫助BAT一線資深工程師成長並利用自身優點創造睡後收入。
- 官方公衆號 | 願碼 | 願碼服務號 | 區塊鏈部落
- 免費加入願碼全思惟工程師社羣 | 任一公衆號回覆「願碼」兩個字獲取入羣二維碼
本文閱讀時長:15minhtml
在本文中,咱們將學習以編程方式執行操做以自動檢索和處理信息。Python requests模塊使得執行這些操做變得很是容易。
本文知識點:python
下載網頁的基本功能包括GET針對URL 發出HTTP 請求。這是任何Web瀏覽器的基本操做。咱們將在此配方中看到如何獲取獲取網頁的簡單請求。程序員
安裝 requests模塊:web
$ echo "requests==2.18.3" >> requirements.txt $ source .venv/bin/activate (.venv) $ pip install -r requirements.txt
>>> import requests
>>> url = 'http://www.columbia.edu/~fdc/sample.html' >>> response = requests.get(url)
>>> response.status_code 200
>>> response.text '\n\n\n ... FULL BODY ... \n'
>>> response.request.headers {'User-Agent': 'python-requests/2.18.4', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'} >>> response.headers {'Date': 'Fri, 25 May 2018 21:51:47 GMT', 'Server': 'Apache', 'Last-Modified': 'Thu, 22 Apr 2004 15:52:25 GMT', 'Accept-Ranges': 'bytes', 'Vary': 'Accept-Encoding,User-Agent', 'Content-Encoding': 'gzip', 'Content-Length': '8664', 'Keep-Alive': 'timeout=15, max=85', 'Connection': 'Keep-Alive', 'Content-Type': 'text/html', 'Set-Cookie': 'BIGipServer~CUIT~www.columbia.edu-80-pool=1764244352.20480.0000; expires=Sat, 26-May-2018 03:51:47 GMT; path=/; Httponly'}
操做requests很是簡單; GET在這種狀況下,經過URL 執行操做。這將返回result能夠分析的對象。主要元素是status_code身體內容,能夠表示爲text。編程
能夠在request現場檢查完整請求:瀏覽器
>>> response.request >>> response.request.url 'http://www.columbia.edu/~fdc/sample.html'
咱們將使用Beautiful Soup模塊將HTML文本解析爲能夠分析的內存對象。咱們須要使用該 beautifulsoup4 包來使用可用的Python 3版本。將軟件包添加到您requirements.txt的虛擬環境中並安裝依賴項:服務器
$ echo "beautifulsoup4==4.6.0" >> requirements.txt $ pip install -r requirements.txt
>>> import requests >>> from bs4 import BeautifulSoup
>>> URL = 'http://www.columbia.edu/~fdc/sample.html' >>> response = requests.get(URL) >>> response
>>> page = BeautifulSoup(response.text, 'html.parser')
>>> page.title Sample Web Page >>> page.title.string 'Sample Web Page'
>>> page.find_all('h3') [CONTENTS, 1. Creating a Web Page, 2. HTML Syntax, 3. Special Characters, 4. Converting Plain Text to HTML, 5. Effects, 6. Lists, 7. Links, 8. Tables, 9. Installing Your Web Page on the Internet, 10. Where to go from here]
標籤:網絡
>>> link_section = page.find('a', attrs={'name': 'links'}) >>> section = [] >>> for element in link_section.next_elements: ... if element.name == 'h3': ... break ... section.append(element.string or '') ... >>> result = ''.join(section) >>> result '7. Links\n\nLinks can be internal within a Web page (like to\nthe Table of ContentsTable of Contents at the top), or they\ncan be to external web pages or pictures on the same website, or they\ncan be to websites, pages, or pictures anywhere else in the world.\n\n\n\nHere is a link to the Kermit\nProject home pageKermit\nProject home page.\n\n\n\nHere is a link to Section 5Section 5 of this document.\n\n\n\nHere is a link to\nSection 4.0Section 4.0\nof the C-Kermit\nfor Unix Installation InstructionsC-Kermit\nfor Unix Installation Instructions.\n\n\n\nHere is a link to a picture:\nCLICK HERECLICK HERE to see it.\n\n\n'
請注意,沒有HTML標記; 這都是原始文本。架構
第一步是下載頁面。而後,能夠解析原始文本,如步驟3所示。結果 page 對象包含解析的信息。BeautifulSoup容許咱們搜索HTML元素。它能夠搜索第一個.find() 或返回列表 .find_all()。在步驟5中,它搜索具備特定屬性的特定標籤name=link。以後,它繼續迭代,.next_elements直到找到下一個h3標記,標記該部分的結尾。併發
提取每一個元素的文本並最終組成單個文本。請注意or,避免存儲None,當元素沒有文本時返回。
鑑於超連接頁面的性質,從一個已知的地方開始,並在連接到其餘頁面後,在抓取網絡時,這是一個很是重要的工具。
爲此,咱們抓取一個尋找小短語的頁面,並打印包含它的任何段落。咱們只會搜索屬於同一網站的網頁。即只有以www.somesite.com開頭的網址。咱們不會關注指向外部網站的連接。
咱們將使用GitHub倉庫中提供的準備示例做爲示例。 下載整個站點並運行包含的腳本。
$ python simple_delay_server.py
這爲URL中的站點提供服務http://localhost:8000。您能夠在瀏覽器上查看它。這是一個有三個條目的簡單博客。大部分都是無趣的,但咱們添加了幾個包含關鍵字的段落python。
... def process_link(source_link, text): logging.info(f'Extracting links from {source_link}') parsed_source = urlparse(source_link) result = requests.get(source_link) # Error handling. See GitHub for details ... page = BeautifulSoup(result.text, 'html.parser') search_text(source_link, page, text) return get_links(parsed_source, page) def get_links(parsed_source, page): '''Retrieve the links on the page''' links = [] for element in page.find_all('a'): link = element.get('href') # Validate is a valid link. See GitHub for details ... links.append(link) return links
$ python crawling_web_step1.py https://localhost:8000/ -p python Link http://localhost:8000/: --> A smaller article , that contains a reference to Python Link http://localhost:8000/files/5eabef23f63024c20389c34b94dee593-1.html: --> A smaller article , that contains a reference to Python Link http://localhost:8000/files/33714fc865e02aeda2dabb9a42a787b2-0.html: --> This is the actual bit with a python reference that we are interested in. Link http://localhost:8000/files/archive-september-2018.html: --> A smaller article , that contains a reference to Python Link http://localhost:8000/index.html: --> A smaller article , that contains a reference to Python
$ python crawling_web_step1.py http://localhost:8000/ -p crocodile
讓咱們看看腳本的每一個組件:
它會下載文件,並檢查狀態是否正確,以跳過連接斷開等錯誤。它還會檢查類型(如上所述 Content-Type)是否爲HTML頁面以跳過PDF和其餘格式。最後,它將原始HTML解析爲一個BeautifulSoup對象。
它還使用解析源連接urlparse,所以稍後在步驟4中,它能夠跳過對外部源的全部引用。 urlparse將URL劃分爲其組成元素:
>>> from urllib.parse import urlparse >>> >>> urlparse('http://localhost:8000/files/b93bec5d9681df87e6e8d5703ed7cd81-2.html') ParseResult(scheme='http', netloc='localhost:8000', path='/files/b93bec5d9681df87e6e8d5703ed7cd81-2.html', params='', query='', fragment='')
它在解析的對象中搜索指定的文本。請注意,搜索僅做爲a regex並在文本中完成。它打印生成的匹配項,包括source_link引用找到匹配項的URL:
for element in page.find_all(text=re.compile(text)): print(f'Link {source_link}: --> {element}')
它在解析的頁面中搜索全部元素,並檢索href元素,但僅檢索具備此類href元素且是徹底限定URL(以...開頭http)的元素。這將刪除不是URL的'#'連接,例如連接或頁面內部的連接。
進行額外檢查以檢查它們是否與原始連接具備相同的來源,而後將它們註冊爲有效連接。該netloc屬性容許檢測連接來自與步驟2中生成的已解析URL相同的URL域。
最後,返回連接,將它們添加到步驟1中描述的循環中。
有時網頁不向公衆開放,但以某種方式受到保護。最基本的方面是使用基本的HTTP身份驗證,它幾乎集成到每一個Web服務器中,它是一個用戶/密碼架構。
咱們能夠在https://httpbin.org中測試這種... 。它有一個路徑,/basic-auth/{user}/{password}強制進行身份驗證,並指定用戶和密碼。這對於理解身份驗證的工做原理很是方便。
>>> import requests
>>> requests.get('https://httpbin.org/basic-auth/user/psswd', auth=('user', 'psswd'))
>>> requests.get('https://httpbin.org/basic-auth/user/psswd', auth=('user', 'wrong'))
>>> requests.get('https://user:psswd@httpbin.org/basic-auth/user/psswd') >>> requests.get('https://user:wrong@httpbin.org/basic-auth/user/psswd')
從網頁下載信息所花費的大部分時間一般都在等待。一個請求從咱們的計算機發送到任何服務器將處理它,直到響應組成並返回到咱們的計算機,咱們不能作太多的事情。
在本文中,咱們將看到如何並行下載頁面列表,並等待它們所有準備好。咱們將使用故意慢的服務器來顯示這一點。
咱們將獲取用於抓取和搜索關鍵字的代碼,利用futuresPython 3 的功能同時下載多個頁面。A future是表示值的承諾的對象。這意味着您在後臺執行代碼時會當即收到對象。只有在特別要求其.result()代碼塊時才能得到它。
要生成a future,您須要一個名爲executor的後臺引擎。一旦建立,就會 submit有一個函數和參數來檢索它future。結果的檢索能夠根據須要延遲,容許futures連續生成幾個,並等待全部結束,並行執行它們,而不是建立一個,等到它完成,建立另外一個,依此類推。
有幾種方法能夠建立執行程序; 咱們將使用ThreadPoolExecutor,它將使用線程。
咱們將使用GitHub倉庫中提供的準備示例做爲示例。下載整個站點並運行包含的腳本
$ python simple_delay_server.py -d 2
這爲URL中的站點提供服務 http://localhost:8000。您能夠在瀏覽器上查看它。這是一個簡單的博客,有三個條目。大部分都是無趣的,但咱們添加了幾個包含關鍵字的段落 python。該參數-d 2使服務器故意變慢,模擬鏈接錯誤。
$ time python crawling_web_step1.py http://localhost:8000/ ... REMOVED OUTPUT real 0m12.221s user 0m0.160s sys 0m0.034s
$ time python speed_up_step1.py -w 1 ... REMOVED OUTPUT real 0m16.403s user 0m0.181s sys 0m0.068s
$ time python speed_up_step1.py -w 2 ... REMOVED OUTPUT real 0m10.353s user 0m0.199s sys 0m0.068s
$ time python speed_up_step1.py -w 5 ... REMOVED OUTPUT real 0m6.234s user 0m0.171s sys 0m0.040s
建立併發請求的主要引擎是主要功能。請注意,其他代碼基本上不受影響(除了返回process_link函數中的源連接)。這是處理併發引擎的代碼的相關部分:
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor: while to_check: futures = [executor.submit(process_link, url, to_search) for url in to_check] to_check = [] for data in concurrent.futures.as_completed(futures): link, new_links = data.result() checked_links.add(link) for link in new_links: if link not in checked_links and link not in to_check: to_check.append(link) max_checks -= 1 if not max_checks: return
該with背景下產生的工人池,並指定其編號。在內部,建立包含要檢索的全部URL的期貨列表。該.as_completed()函數返回已完成的期貨,而後有一些工做處理獲取新找到的連接並檢查是否須要添加它們以進行檢索。此過程相似於抓取Web 配方中顯示的過程。
該過程再次開始,直到檢索到足夠的連接或沒有要檢索的連接。