Requests :唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。
直接调用requests.get
import requests
response = requests.get('https://www.baidu.com')
import requests
params = {'wd': 'python'}
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4090.0 Safari/537.36 Edg/83.0.467.0'}
# params: 接受一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode()
response = requests.get('https://www.baidu.com', params=params, headers=headers)
# 查看响应内容,response.text返回的是Unicode格式的数据
print(response.text)
# 查看响应内容,response.content返回的是字节流数据
print(response.content.decode('utf-8'))
# 查看完整url地址
print(response.url)
# 查看响应头部字符编码
print(response.encoding)
# 查看响应码
print(response.status_code)
直接调用requests.post,如果返回的是json数据,可以调用response.json()来将json字符串转为字典或列表
下面是爬取拉勾网的一个示例,记得请求头添加Cookie,才能成功爬取到
import requests
data = {'first': 'true',
'pn': '1',
'kd': 'python'}
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/83.0.4090.0 Safari/537.36 Edg/83.0.467.0',
'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
'Cookie': 'user_trace_token=20200331183800-0c1f510a-ae9a-4f04-b70d-e17f9edec031; '
'LGUID=20200331183800-b8eca414-b7b2-479d-8100-71fff41d8087; _ga=GA1.2.17010052.1585651081; '
'index_location_city=%E5%85%A8%E5%9B%BD; lagou_utm_source=B; _gid=GA1.2.807051168.1585805257; '
'sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22171302b7caa67e-0dedc0121b2532-255e0c45'
'-2073600-171302b7cabb9c%22%2C%22%24device_id%22%3A%22171302b7caa67e-0dedc0121b2532-255e0c45'
'-2073600-171302b7cabb9c%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B'
'%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22'
'%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5'
'%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; '
'JSESSIONID=ABAAABAABFIAAAC7D7CECCAFCFFA1FCBF3CB10D8EA6A189; '
'WEBTJ-ID=20200403095906-1713dc35e58a75-0b564b9cba1732-23580c45-2073600-1713dc35e598e; PRE_UTM=; '
'PRE_HOST=; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; '
'LGSID=20200403095905-8201da05-4bb8-4e93-97bf-724ea6f758af; '
'PRE_SITE=https%3A%2F%2Fwww.lagou.com; _gat=1; '
'Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1585651082,1585879146; TG-TRACK-CODE=index_search; '
'X_HTTP_TOKEN=0b356dc3463713117419785851e40fa7a09468f3f0; '
'Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1585879149; '
'LGRID=20200403095908-4f1711b9-3e7e-4d54-a400-20c76b57f327; '
'SEARCH_ID=b875e8b91a764d63a2dc98d822ca1f85'}
response = requests.post('https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false',
headers=headers,
data=data)
print(response.json())
这里在基础中已经讲到过,使用requests只需要两行代码,非常方便
import requests
proxy = {'http': '59.44.78.30:54069'}
response = requests.get('http://httpbin.org/ip', proxies=proxy)
print(response.text)
使用session在多次请求中共享cookie,可以发现相比使用urllib代码变得特别简洁
import requests
headers = {'User-Agent': ''}
data = {'email': '',
'password': ''}
login_url = 'http://www.renren.com/PLogin.do'
profile_url = 'http://www.renren.com/880151247/profile'
session = requests.Session()
session.post(login_url, data=data, headers=headers)
response = session.get(profile_url)
with open('renren.html', 'w', encoding='utf-8') as f:
f.write(response.text)
对于那些没有被信任的SSL证书的网站,可以在requests.get和requests.post中设置参数verify=False来进行访问
xpath(XML Path Language)是一门在XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行访问。
XPath使用路径表达式来选取XML文档中的节点或者节点集,这些路径表达式和我们在常规的电脑文件系统中的表示式非常类似。
表达式 | 描述 | 示例 | 结果 |
nodename | 选取此节点的所有子节点 | bookstore | 选取bookstore下所有的子节点 |
/ | 如果在最前面,代表从根节点选取,否则选择某节点下的某个节点 | /bookstore | 选取根元素下所有的bookstore节点 |
// | 从全局节点中选择节点,随便在哪个位置 | //book | 从全局节点中找到所有的book节点 |
@ | 选取某个节点的属性 | //book[@price] | 选择所有拥有price属性的book节点 |
谓语用来查找某个特定的节点或者包含某个指定节点的值的节点,被嵌在方括号中。
路径表达式 | 描述 |
/bookstore/book[1] | 选取bookstore下的第一个book元素 |
/booksotre/book[last()] | 选取bookstore下的最后一个book元素 |
/bookstore/book[position()❤️] | 选取bookstore下前面两个book元素 |
//book[@price] | 选择所有拥有price属性的book节点 |
//book[@price=10] | 选取所有属性price=10的book元素 |
通配符 | 描述 | 示例 | 结果 |
* | 匹配任意节点 | /bookstore/* | 选取bookstore下的所有子元素 |
@* | 匹配节点中的任何属性 | //book[@*] | 选取所有带有属性的book元素 |
通过在路径表达式中使用|运算符,可以选取若干个路径
//bookstore/book | //book/title
# 选取多个book元素以及book元素下的title元素
运算符 | 描述 | 实例 | 返回值 |
| | 计算两个节点集 | //book | //cd | 返回所有拥有book和cd元素的节点集 |
+,-,*,div | 加,减,乘,除 | 6+1, 6-1, 6 * 1, 6 div 1 | 7, 5, 6, 6 |
=, !=, <, <=, >, >= | - | - | 返回false或true |
or, and | 或,与 | - | 返回false或true |
mod | 计算除法的余数 | 5 mod 2 | 1 |
//div[contains(@class, 'job_detail')]
3.谓词中的下标从1开始。
lxml是一个HTML/XML的解析器,主要功能是如何解析和提取HTML/XML数据。
1,解析html字符串:使用lxml.etree.HTML进行解析
from lxml import etree
htmlElement = etree.HTML(text)
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
2,解析html文件:使用lxml.etree.parse进行解析
htmlElement = etree.parse('tencent.xml')
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
这个函数默认使用XML解析器,所以如果碰到不规范的HTML代码的时候就会解析错误,这时候要创建HTML解析器
parser = etree.HTMLParser(encoding='utf-8')
htmlElement = etree.parse('tencent.xml', parser=parser)
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
from lxml import etree
parser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('tencent.html', parser=parser)
trs = html.xpath('//tr')
for tr in trs:
print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))
tr = html.xpath('//tr[2]')[0]
print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))
trs = html.xpath("//tr[@class='even']")
for tr in trs:
print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))
aList = html.xpath('//a/@href')
for a in aList:
print('http://hr.tencent.com/' + a)
注我——个人公众号:后端技术漫谈
我目前是一名后端开发工程师。主要关注后端开发,数据安全,网络爬虫,物联网,边缘计算等方向。
原创博客主要内容
image
最近做了一个python3作业题目,涉及到:
涉及到的库有:
放出代码方便大家快速参考,实现一个小demo。
搜索引擎的设计与实现
["http://fiba.qq.com/a/20190420/001968.htm", "http://sports.qq.com/a/20190424/000181.htm", "http://sports.qq.com/a/20190423/007933.htm", "http://new.qq.com/omn/SPO2019042400075107"]
1 "http:xxxxxx.htm" 3 2 "https:xxxx.htm" 2 3 "https:xxxxx.htm" 1
代码实现的主要步骤是:
import requests from bs4 import BeautifulSoup import json import re import jieba import time USER_AGENT = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) ' 'Chrome/20.0.1092.0 Safari/536.6'} URL_TIMEOUT = 10 SLEEP_TIME = 2 # dict_result格式:{"1": # {"url": "xxxxx", "word": {"word1": x, "word2": x, "word3": x}} # "2": # {"url": "xxxxx", "word": {"word1": x, "word2": x, "word3": x}} # } dict_result = {} # dict_search格式:[ # [url, count] # [url, count] # ] list_search_result = [] def crawler(list_URL): for i, url in enumerate(list_URL): print("网页爬取:", url, "...") page = requests.get(url, headers=USER_AGENT, timeout=URL_TIMEOUT) page.encoding = page.apparent_encoding # 防止编码解析错误 result_clean_page = bs4_page_clean(page) result_chinese = re_chinese(result_clean_page) # print("网页中文内容:", result_chinese) dict_result[i + 1] = {"url": url, "word": jieba_create_index(result_chinese)} print("爬虫休眠中...") time.sleep(SLEEP_TIME) def bs4_page_clean(page): print("正则表达式:清除网页标签等无关信息...") soup = BeautifulSoup(page.text, "html.parser") [script.extract() for script in soup.findAll('script')] [style.extract() for style in soup.findAll('style')] reg1 = re.compile("<[^>]*>") content = reg1.sub('', soup.prettify()) return str(content) def re_chinese(content): print("正则表达式:提取中文...") pattern = re.compile(u'[\u1100-\uFFFD]+?') result = pattern.findall(content) return ''.join(result) def jieba_create_index(string): list_word = jieba.lcut_for_search(string) dict_word_temp = {} for word in list_word: if word in dict_word_temp: dict_word_temp[word] += 1 else: dict_word_temp[word] = 1 return dict_word_temp def search(string): for k, v in dict_result.items(): if string in v["word"]: list_search_result.append([v["url"], v["word"][string]]) # 使用词频对列表进行排序 list_search_result.sort(key=lambda x: x[1], reverse=True) if __name__ == "__main__": list_URL_sport = input("请输入网址列表:") list_URL_sport = list_URL_sport.split(",") print(list_URL_sport) # 删除输入的网页双引号 for i in range(len(list_URL_sport)): list_URL_sport[i] = list_URL_sport[i][1:-1] print(list_URL_sport) # list_URL_sport = ["http://fiba.qq.com/a/20190420/001968.htm", # "http://sports.qq.com/a/20190424/000181.htm", # "http://sports.qq.com/a/20190423/007933.htm", # "http://new.qq.com/omn/SPO2019042400075107"] time_start_crawler = time.time() crawler(list_URL_sport) time_end_crawler = time.time() print("网页爬取和分析时间:", time_end_crawler - time_start_crawler) word = input("请输入查询的关键词:") time_start_search = time.time() search(word) time_end_search = time.time() print("检索时间:", time_end_search - time_start_search) for i, row in enumerate(list_search_result): print(i+1, row[0], row[1]) print("词频信息:") print(json.dumps(dict_result, ensure_ascii=False))
image
我目前是一名后端开发工程师。主要关注后端开发,数据安全,网络爬虫,物联网,边缘计算等方向。
微信:yangzd1102
Github:@qqxx6661
个人博客:
原创博客主要内容
个人公众号:后端技术漫谈
如果文章对你有帮助,不妨收藏起来并转发给您的朋友们~
从事前端开发过程中,浏览器作为最重要的开发环境,浏览器基础是是前端开发人员必须掌握的基础知识点,它贯穿着前端的整个网络体系。对浏览器原理的了解,决定着编写前端代码性能的上限。浏览器作为JS的运行环境,学习总结下现代浏览器的相关知识
前言
经常听说浏览器内核,浏览器内核究竟是什么,以及它做了什么。我们将来了解下浏览器的主要组成部分、现代浏览器的主要架构、浏览器内核、浏览器内部是如何工作的
1 浏览器
现代浏览器结构如下:
The browser's main component
The User Interface
主要提供用户与Browser Engine交互的方法。其中包括:地址栏(address bar)、向前/退后按钮、书签菜单等等。浏览器除了渲染请求页面的窗口外的所有地方都属于The User Interface
The Browser Engine
协调(主控)UI和the Rendering Engine,在他们之间传输指令。 提供对The Rendering Engine的高级接口,一方面它提供初始化加载Url和其他高级的浏览器动作(如刷新、向前、退后等)方法。另一方面Browser Engine也为User Interface提供各种与错误、加载进度相关的消息。
The Rendering Engine
为给定的URL提供可视化的展示。它解析JavaScript、Html、Xml,并且User Interface中展示的layout。其中关键的组件是Html解析器,它可以让Rendering Engine展示差乱的Html页面。 值得注意:不同的浏览器使用不同的Rendering Engine。例如IE使用Trident,Firefox使用Gecko,Safai使用Webkit。Chrome和Opera使用Webkit(以前是Blink)
The Networking
基于互联网HTTP和FTP协议,处理网络请求。网络模块负责Internet communication and security,character set translations and MIME type resolution。另外网络模块还提供获得到文档的缓存,以减少网络传输。为所有平台提供底层网络实现,其提供的接口与平台无关
The JavaScript Interpreter
解释和运行网站上的js代码,得到的结果传输到Rendering Engine来展示。
The UI Backend
用于绘制基本的窗口小部件,比如组合框和窗口。而在底层使用操作系统的用户界面方法,并公开与平台无关的接口。
The Data Storage
管理用户数据,例如书签、cookie和偏好设置等。
2 主流浏览器的架构
2.1 FireFox
FireFox的架构
可以看到火狐浏览器的渲染引擎(Rendering Engine)使用的是Gecko;XML Parser解析器是Expat;Java Script解释器是Spider-Monkey(c语言实现)
2.2 Chrome
Chrome的架构
渲染引擎Rendering Engine使用的是WebKit
XML Parser: libXML解析XML,libXSLT处理XSLT
JS解释器使用C++实现的V8引擎,
2.3 IE
IE的架构
渲染引擎主要是Trident
Scripting Engine有JScript和VBScript
3 浏览器内核
浏览器最重要或者说核心的部分是“Rendering Engine”,可大概译为“渲染引擎”,不过我们一般习惯将之称为“浏览器内核”。主要包括以下线程:
3.1 浏览器 GUI 渲染线程,主要包括:
HTML Parser 解析HTML文档,将元素转换为树结构DOM节点,称之为Content Tree
CSS Parser 解析Style数据,包括外部的CSS文件以及在HTML元素中的样式,用于创建另一棵树,调用“Render Tree”
Layout过程 为每个节点计算出在屏幕中展示的准确坐标
Painting 遍历Render Tree,调用UI Backend提供的接口绘制每个节点
3.2 JavaScript 引擎线程
JS引擎线程负责解析Javascript脚本,运行代码 JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞
a) 减少 JavaScript 加载对 DOM 渲染的影响(将 JavaScript 代码的加载逻辑放在 HTML 文件的尾部,减少对渲染引擎呈现工作的影响; b) 避免重排,减少重绘(避免白屏,或者交互过程中的卡顿; c) 减少 DOM 的层级(可以减少渲染引擎工作过程中的计算量; d) 使用 requestAnimationFrame 来实现视觉变化(一般来说我们会使用 setTimeout 或 setInterval 来执行动画之类的视觉变化,但这种做法的问题是,回调将在帧中的某个时点运行,可能刚好在末尾,而这可能经常会使我们丢失帧,导致卡顿)
3.3 浏览器定时触发器线程
浏览器定时计数器并不是由 JavaScript 引擎计数的, 因为 JavaScript 引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确, 因此通过单独线程来计时并触发定时是更为合理的方案
3.4 浏览器事件触发线程
当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待 JavaScript 引擎的处理。这些事件可以是当前执行的代码块如定时任务、也可来自浏览器内核的其他线程如鼠标点击、AJAX 异步请求等,但由于 JavaScript 的单线程关系所有这些事件都得排队等待 JavaScript 引擎处理。
3.5 浏览器 http 异步请求线程
在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求, 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 JavaScript 引擎的处理队列中等待处理。
4 以Chrome浏览器为例,演示浏览器内部如何工作
上面铺垫了这么多理论,下面结合Chrome讲解当用户在地址栏上输入URL后,浏览器内部都做了写什么
4.1 Chrome浏览器中的多进程
打开Chrome 任务管理器,可以看到
Chrome运行的进程
各个进程的功能
• Browser进程
功能:Controls "chrome" part of the application including address bar, bookmarks, back and forward buttons. Also handles the invisible, privileged parts of a web browser such as network requests and file access.
• GPU进程
功能:Handles GPU tasks in isolation from other processes. It is separated into different process because GPUs handles requests from multiple apps and draw them in the same surface.
• 第三方插件进程
功能:Controls any plugins used by the website, for example, flash. 每个插件对应一个进程,当插件运行时创建
• 浏览器渲染进程
功能:Controls anything inside of the tab where a website is displayed. 默认每个标签页创建一个渲染引擎实例。
• V8 Proxy resolver
关于V8 Proxy resolver可查看
group.google.com !topic/net-dev/73f9B5vFphI
Chrome支持使用代理脚本为给定的网址选择代理服务器,包含使用操作系统提供的代理解析程序的多个平台的回退实现。但默认情况下(iOS除外),它使用内置的解析V8执行代理脚本(V8 pac)。今天(截至2015年1月),V8 pac在浏览器进程中运行。这意味着浏览器进程包含一个V8实例,这是一个潜在的安全漏洞。在浏览器进程中允许V8还需要浏览器进程允许写入 - 执行页面。
我们关于将V8 pac迁移到单独进程的建议包括为解析器创建Mojo服务,从实用程序进程导出该服务,以及从浏览器进程创建/连接到该进程。
浏览器进程之间主要通过IPC (Inter Process Communication)通信
4.2 Per-frame renderer processes - Site Isolation
Site Isolation is a recently introduced feature in Chrome that runs a separate renderer process for each cross-site iframe. We’ve been talking about one renderer process per tab model which allowed cross-site iframes to run in a single renderer process with sharing memory space between different sites. Running a.com and b.com in the same renderer process might seem okay. The Same Origin Policy is the core security model of the web; it makes sure one site cannot access data from other sites without consent. Bypassing this policy is a primary goal of security attacks. Process isolation is the most effective way to separate sites. With Meltdown and Spectre, it became even more apparent that we need to separate sites using processes. With Site Isolation enabled on desktop by default since Chrome 67, each cross-site iframe in a tab gets a separate renderer process.
每个iframe是单独的渲染进程
*请认真填写需求信息,我们会在24小时内与您取得联系。