- 来源 | 愿码(ChainDesk.CN)内容编辑
- 愿码Slogan | 连接每个程序员的故事
- 网站 | http://chaindesk.cn
- 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优势创造睡后收入。
- 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
- 免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码
本文阅读时长:15min
在本文中,我们将学习以编程方式执行操作以自动检索和处理信息。Python requests模块使得执行这些操作变得非常容易。
本文知识点:
下载网页的基本功能包括GET针对URL 发出HTTP 请求。这是任何Web浏览器的基本操作。我们将在此配方中看到如何获取获取网页的简单请求。
安装 requests模块:
$ 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:[email protected]/basic-auth/user/psswd')
>>> requests.get('https://user:[email protected]/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 配方中显示的过程。
该过程再次开始,直到检索到足够的链接或没有要检索的链接。