- 来源 | 愿码(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 配方中显示的过程。
该过程再次开始,直到检索到足够的连接或没有要检索的连接。