Python爬虫第一天
什么是爬虫
爬虫与Web后端服务之间的关系
Python爬虫技术相关库
常见的反爬虫策略
爬虫库urllib【重要】
作业
爬虫第二天
回顾知识点
requests库【重点】
数据分析方法之一xpath
绝对路径
相对路径
数据提取
位置条件
属性条件
在Python中应用
作业
爬虫第三天
回顾知识点
requests库
xpath解析
扩展封装ES-SDK
数据的正则分析
扩展Linux文件权限
re面试中的问题
作业
爬虫第四天
回顾知识点
re正则
进程和线程
BS4数据解析
协程爬虫
协程的三种方式
协程第三方框架
动态js渲染
Selenium
Splash
作业
爬虫最五天
回顾知识点
协程的爬虫
Seleinum库
Chrome-headless
Splash渲染
下载镜像
启动镜像
render.html接口
自动化测试
单元测试
集成测试
作业
爬虫第六天
回顾知识点
selenium框架
docker
日志模块进阶
日志格式
日志模块的核心
scrapy框架
scrapy架构组成
scrapy指令
Response类
Request类
作业
爬虫第七天
回顾知识点
scrapy框架
scrapy数据管道
指令方式存储
Pipeline
定量爬虫
基于信号方式
下载中间件
爬虫中间件
下载中间件 [重点]
作业
爬虫第八天
回顾知识点
数据处理
中间件
规则爬虫
规则爬虫【重】
LinkExtractor 类
核心的类
图片管道
使用ImagesPipeline
自定义ImagesPipeline
其它技术点
日志
post请求
Selenium中间件
作业
爬虫第九天
回顾知识点
Selenium下载中间件
分布式爬虫
什么是分布式
常见消息队列
scrapy-redis
爬虫程序部署
scrapyd
docker部署
作业
爬虫第十天
回顾爬虫技术
网络请求
数据解析
数据存储
爬虫框架
mongodb
docker部署
数据结构
常用操作
作业
学习内容:
-
什么是爬虫(Spider)
-
爬虫与Web后端服务之间的关系
-
Python爬虫技术的相关库
-
常见反爬虫的策略
-
爬虫库urllib【重要】
爬虫用于爬取数据, 又称之为。
爬取的数据来源于网络,网络中的数据可以是由(Nginx/Apache)、数据库服务器(MySQL、Redis)、索引库(ElastichSearch)、大数据(Hbase/Hive)、视频/图片库(FTP)、云存储等(OSS)提供的。
爬取的数据是公开的、非盈利的。
使用Python编写的爬虫脚本(程序)可以完成定时、定量、指定目标(Web站点)的数据爬取。主要使用多(单)线程/进程、网络请求库、数据解析、数据存储、任务调度等相关技术。
Python爬虫工程师,可以完成接口测试、功能性测试、性能测试和集成测试。
爬虫使用网络请求库,相当于客户端请求, Web后端服务根据请求响应数据。
爬虫即向Web服务器发起HTTP请求,正确地接收响应数据,然后根据数据的类型(Content-Type)进行数据的解析及存储。
爬虫程序在发起请求前,需要伪造浏览器(User-Agent指定请求头),然后再向服务器发起请求, 响应200的成功率高很多。
网络请求:
-
urllib
-
requests / urllib3
-
selenium(UI自动测试、动态js渲染)
-
appium(手机App 的爬虫或UI测试)
数据解析:
-
re正则
-
xpath
-
bs4
-
json
数据存储:
-
pymysql
-
mongodb
-
elasticsearch
多任务库:
-
多线程 (threading)、线程队列 queue
-
协程(asynio、 gevent/eventlet)
爬虫框架
-
scrapy
-
scrapy-redis 分布式(多机爬虫)
-
UA(User-Agent)策略
-
登录限制(Cookie)策略
-
请求频次(IP代理)策略
-
验证码(图片-云打码,文字或物件图片选择、滑块)策略
-
动态js(Selenium/Splash/api接口)策略
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">from</span> <span style="color:#000000">urllib</span>.<span style="color:#000000">request</span> <span style="color:#770088">import</span> <span style="color:#000000">urlopen</span>
<span style="color:#aa5500"># 发起网络请求</span>
<span style="color:#000000">resp</span> = <span style="color:#000000">urllopen</span>(<span style="color:#aa1111">'http://www.hao123.com'</span>)
<span style="color:#770088">assert</span> <span style="color:#000000">resp</span>.<span style="color:#000000">code</span> == <span style="color:#116644">200</span>
<span style="color:#3300aa">print</span>(<span style="color:#aa1111">'请求成功'</span>)
<span style="color:#aa5500"># 保存请求的网页</span>
<span style="color:#aa5500"># f 变量接收open()函数返回的对象的__enter__()返回结果</span>
<span style="color:#770088">with</span> <span style="color:#3300aa">open</span>(<span style="color:#aa1111">'a.html'</span>, <span style="color:#aa1111">'wb'</span>) <span style="color:#770088">as</span> <span style="color:#000000">f</span>:
<span style="color:#000000">f</span>.<span style="color:#000000">write</span>(<span style="color:#000000">resp</span>.<span style="color:#000000">read</span>())</span></span>
urlopen(url, data=None)可以直接发起url的请求, 如果data不为空时,则默认是POST请求,反之为GET请求。
resp是http.client.HTTPResponse类对象。
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">from</span> <span style="color:#000000">urllib</span>.<span style="color:#000000">request</span> <span style="color:#770088">import</span> <span style="color:#000000">Request</span>
<span style="color:#770088">def</span> <span style="color:#0000ff">search_baidu</span>():
<span style="color:#aa5500"># 网络资源的接口(URL)</span>
<span style="color:#000000">url</span> = <span style="color:#aa1111">'https://www.baidu.com'</span>
<span style="color:#aa5500"># 生成请求对象,封装请求的url和头header</span>
<span style="color:#000000">request</span> = <span style="color:#000000">Request</span>(<span style="color:#000000">url</span>,
<span style="color:#000000">headers</span>={
<span style="color:#aa1111">'Cookie'</span>: <span style="color:#aa1111">'BIDUPSID=16CECBB89822E3A2F26ECB8FC695AFE0; PSTM=1572182457; BAIDUID=16CECBB89822E3A2C554637A8C5F6E91:FG=1; BD_UPN=123253; H_PS_PSSID=1435_21084_30211_30283; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_645EC=6f7aTIObS%2BijtMmWgFQxMF6H%2FhK%2FcpddiytCBDrefRYyFX%2B%2BTpyRMZInx3E'</span>,
<span style="color:#aa1111">'User-Agent'</span>: <span style="color:#aa1111">'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'</span>
})
<span style="color:#000000">response</span> = <span style="color:#000000">urlopen</span>(<span style="color:#000000">request</span>) <span style="color:#aa5500"># 发起请求</span>
<span style="color:#770088">assert</span> <span style="color:#000000">response</span>.<span style="color:#000000">code</span> == <span style="color:#116644">200</span>
<span style="color:#3300aa">print</span>(<span style="color:#aa1111">'请求成功'</span>)
<span style="color:#aa5500"># 读取响应的数据</span>
<span style="color:#000000">bytes_</span> = <span style="color:#000000">response</span>.<span style="color:#000000">read</span>()
<span style="color:#aa5500"># 将响应的数据写入文件中</span>
<span style="color:#770088">with</span> <span style="color:#3300aa">open</span>(<span style="color:#aa1111">'index.html'</span>, <span style="color:#aa1111">'wb'</span>) <span style="color:#770088">as</span> <span style="color:#000000">file</span>:
<span style="color:#000000">file</span>.<span style="color:#000000">write</span>(<span style="color:#000000">bytes_</span>)</span></span>
任务1:收集Http协议的报文头的哪些Key
此模块有两个核心的函数:
-
quote() 仅对中文字符串进行url编码;
-
urlencode() 可以针对一个字典中所有的values进行编码,然后转成key=value&key=value的字符串。
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa1111">"""</span>
<span style="color:#aa1111">复杂的GET请求,多页面请求下载</span>
<span style="color:#aa1111">"""</span>
<span style="color:#770088">from</span> <span style="color:#000000">urllib</span>.<span style="color:#000000">request</span> <span style="color:#770088">import</span> <span style="color:#000000">Request</span>, <span style="color:#000000">urlopen</span>
<span style="color:#770088">from</span> <span style="color:#000000">urllib</span>.<span style="color:#000000">parse</span> <span style="color:#770088">import</span> <span style="color:#000000">urlencode</span>
<span style="color:#770088">import</span> <span style="color:#000000">ssl</span>
<span style="color:#770088">import</span> <span style="color:#000000">time</span>
<span style="color:#000000">ssl</span>.<span style="color:#000000">_create_default_https_context</span> = <span style="color:#000000">ssl</span>.<span style="color:#000000">_create_unverified_context</span>
<span style="color:#000000">url</span> = <span style="color:#aa1111">'https://www.baidu.com/s?'</span>
<span style="color:#000000">headers</span> = {
<span style="color:#aa1111">'User-Agent'</span>: <span style="color:#aa1111">'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'</span>,
<span style="color:#aa1111">'Cookie'</span>: <span style="color:#aa1111">'BIDUPSID=16CECBB89822E3A2F26ECB8FC695AFE0; PSTM=1572182457; BAIDUID=16CECBB89822E3A2C554637A8C5F6E91:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1573184257; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; H_PS_PSSID=1435_21084_30211_30283; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; delPer=0; PSINO=1; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; APPGUIDE_8_2_2=1; yjs_js_security_passport=0927713bf2c240ca607108086d07729426db4dbb_1577084843_js; __yjsv5_shitong=1.0_7_c3620451e4363f4aed30cbe954abf8942810_300_1577084847314_223.255.14.197_2d7151e0; from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%2C%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D'</span>,
<span style="color:#aa1111">'x-requested-with'</span>: <span style="color:#aa1111">'XMLHttpRequest'</span>
}
<span style="color:#000000">params</span> = {
<span style="color:#aa1111">'wd'</span>: <span style="color:#aa1111">''</span>,
<span style="color:#aa1111">'pn'</span>: <span style="color:#116644">0</span> <span style="color:#aa5500"># 0, 10, 20, 30 ... = (n-1)*10</span>
}
<span style="color:#770088">def</span> <span style="color:#0000ff">pages_get</span>(<span style="color:#000000">wd</span>):
<span style="color:#000000">params</span>[<span style="color:#aa1111">'wd'</span>] = <span style="color:#000000">wd</span>
<span style="color:#770088">for</span> <span style="color:#000000">page</span> <span style="color:#770088">in</span> <span style="color:#3300aa">range</span>(<span style="color:#116644">1</span>, <span style="color:#116644">101</span>):
<span style="color:#000000">params</span>[<span style="color:#aa1111">'pn'</span>] = (<span style="color:#000000">page</span><span style="color:#981a1a">-</span><span style="color:#116644">1</span>)<span style="color:#981a1a">*</span><span style="color:#116644">10</span>
<span style="color:#000000">page_url</span> = <span style="color:#000000">url</span><span style="color:#981a1a">+</span><span style="color:#000000">urlencode</span>(<span style="color:#000000">params</span>)
<span style="color:#000000">resp</span> = <span style="color:#000000">urlopen</span>(<span style="color:#000000">Request</span>(<span style="color:#000000">page_url</span>,
<span style="color:#000000">headers</span>=<span style="color:#000000">headers</span>))
<span style="color:#770088">assert</span> <span style="color:#000000">resp</span>.<span style="color:#000000">code</span> == <span style="color:#116644">200</span>
<span style="color:#000000">file_name</span> = <span style="color:#aa1111">'baidu_pages/%s-%s.html'</span> <span style="color:#981a1a">%</span> (<span style="color:#000000">wd</span>, <span style="color:#000000">page</span>)
<span style="color:#770088">with</span> <span style="color:#3300aa">open</span>(<span style="color:#000000">file_name</span>, <span style="color:#aa1111">'wb'</span>) <span style="color:#770088">as</span> <span style="color:#000000">f</span>:
<span style="color:#000000">bytes_</span> = <span style="color:#000000">resp</span>.<span style="color:#000000">read</span>()
<span style="color:#000000">f</span>.<span style="color:#000000">write</span>(<span style="color:#000000">bytes_</span>)
<span style="color:#3300aa">print</span>(<span style="color:#aa1111">f'{file_name} 写入成功!'</span>)
<span style="color:#000000">time</span>.<span style="color:#000000">sleep</span>(<span style="color:#116644">0.5</span>)
<span style="color:#3300aa">print</span>(<span style="color:#aa1111">'下载 %s 100页成功!'</span> <span style="color:#981a1a">%</span> <span style="color:#000000">wd</span>)
<span style="color:#770088">if</span> <span style="color:#000000">__name__</span> == <span style="color:#aa1111">'__main__'</span>:
<span style="color:#000000">pages_get</span>(<span style="color:#aa1111">'Python3.6'</span>)</span></span>
urllib的请求处理器,主要用于urllib.request.build_opener()
函数参数,表示构造一个由不同处理组成的伪浏览器。
处理Http协议的请求处理。
处理Cookie的处理器,创建类实例时,需要提供http.cookiejar.CookieJar
类的实例对象。
作业
-
写出Python上下文的两个核心函数
<span style="background-color:#f8f8f8"><span style="color:#000000">__enter__</span>(<span style="color:#0055aa">self</span>) <span style="color:#000000">__exit__</span>(<span style="color:#0055aa">self</span>, <span style="color:#000000">except_type</span>, <span style="color:#000000">except_value</span>, <span style="color:#000000">except_tb</span>)</span>
-
写出正则中的(), [] , {} 三个符号的作用
<span style="background-color:#f8f8f8">( ) 用于分组的符号 [ ] 指定匹配字符的范围,如 [a-c_B-F] { } 指定匹配的长度(量词表示)</span>
-
写出pymysql.Connect()连接数据库的核心参数
<span style="background-color:#f8f8f8"><span style="color:#000000">Connect</span>(<span style="color:#000000">host</span>, <span style="color:#000000">port</span>=<span style="color:#116644">3306</span>, <span style="color:#000000">user</span>, <span style="color:#000000">password</span>, <span style="color:#000000">db</span>, <span style="color:#000000">charset</span>)</span>
-
豆瓣动作电影排行榜
-
肯德基店铺位置
爬虫第二天
回顾知识点
核心的网络请求库 -> urllib库
-
urllib.request 模块
-
urlopen(url | request: Request, data=None) data是bytes类型
-
urlretrieve(url, filename) 下载url的资源到指定的文件
-
build_opener(*handlder) 构造浏览器对象
-
opener.open(url|request, data=None) 发起请求
-
-
Request 构造请求的类
data={ 'wd': '' } # urlencode(data) => 'wd=%f5%e6%e6%f5%e6%e6' request = Request(url, data=urlencode(data).encode())
-
HTTPHandler HTTP协议请求处理器
-
ProxyHandler(proxies={'http': 'http://proxy_ip:port'}) 代理处理
-
HTTPCookieProcessor(CookieJar())
-
http.cookiejar.CookieJar 类
-
-
-
urllib.parse模块
-
quote(txt) 将中文字符串转成url编码
-
urlencode(query: dict) 将参数的字典转成url编码,结果是key=value&key=value形式,即以
application/x-www-form-urlencoded
作为url编码类型。
-
requests库【重点】
requests库也是一个网络请求库, 基于urllib和urllib3封装的便捷使用的网络请求库。
安装环境
pip install requests -i https://mirrors.aliyun.com/pypi/simple
核心的函数
-
requests.request() 所有请求方法的基本方法
以下是request()方法的参数说明
-
method: str 指定请求方法, GET, POST, PUT, DELETE
-
url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
-
params: dict , 用于GET请求的查询参数(Query String params);
-
data: dict , 用于POST/PUT/DELETE 请求的表单参数(Form Data)
-
json: dict 用于上传json数据的参数, 封装到body(请求体)中。请求头的Content-Type默认设置为
application/json
-
files: dict, 结构 {'name': file-like-object | tuple}, 如果是tuple, 则有三种情况:
-
('filename', file-like-object)
-
('filename', file-like-object, content_type)
-
('filename', file-like-object, content_type, custom-headers)
指定files用于上传文件, 一般使用post请求,默认请求头的
Content-Type
为multipart/form-data
类型。 -
-
headers/cookies : dict
-
proxies: dict , 设置代理
-
auth: tuple , 用于授权的用户名和口令, 形式('username', 'pwd')
-
-
requests.get() 发起GET请求, 查询数据
可用参数:
-
url
-
params
-
json
-
headers/cookies/auth
-
-
requests.post() 发起POST请求, 上传/添加数据
可用参数:
-
url
-
data/files
-
json
-
headers/cookies/auth
-
-
requests.put() 发起PUT请求, 修改或更新数据
-
requests.patch() HTTP幂等性的问题,可能会出现重复处理, 不建议使用。用于更新数据
-
requests.delete() 发起DELETE请求,删除数据
requests.Respose
以上的请求方法返回的对象类型是Response, 对象常用的属性如下:
-
status_code 响应状态码
-
url 请求的url
-
headers : dict 响应的头, 相对于urllib的响应对象的getheaders(),但不包含cookie。
-
cookies: 可迭代的对象,元素是Cookie类对象(name, value, path)
-
text : 响应的文本信息
-
content: 响应的字节数据
-
encoding: 响应数据的编码字符集, 如utf-8, gbk, gb2312
-
json(): 如果响应数据类型为
application/json
,则将响应的数据进行反序化成python的list或dict对象。-
扩展-javascript的序列化和反序列化
-
JSON.stringify(obj) 序列化
-
JSON.parse(text) 反序列化
-
-
xpath属于xml/html解析数据的一种方式, 基于元素(Element)的树形结构(Node > Element)。选择某一元素时,根据元素的路径选择,如
/html/head/title
获取<title>
标签。
绝对路径
从根标签开始,按tree结构依次向下查询。
如 /html/body/table/tbody/tr。
相对路径
相对路径可以有以下写法
-
相对于整个文档
//img
查找出文档中所有的
<img>
标签元素 -
相对于当前节点
//table
假如当前节点是
<table>
, 查找它的<img>
的路径的写法.//img
数据提取
-
提取文本
//title/text()
-
提取属性
//img/@href
位置条件
获取网页中的数据类型与字符集, 获取第一个<meta>
标签
//meta[1]//@content
获取最后一个<meta>
标签
//meta[last()]//@content
获取倒数第二个<meta>
标签
//meta[position()-2]//@content
获取前三个<meta>
标签
//meta[position()<3]//@content
属性条件
查找 class为circle-img
的<img>
标签
//img[@class="circle-img"]
在Python中应用
安装包 pip install lxml
作业
-
写出urllib库的请求处理器有哪些类(尽量写全路径)
-
urllib.request.HTTPHandler
-
urllib.request.HTTPCookieProcessor
-
urllib.request.ProxyHandler
-
-
写出json.loads()和pickle.loads()返回的数据类型
-
json.loads() 返回list或dict, 加载的是字符串
-
pickle.loads() 返回是python中的对象, 加载的是字节数组 bytes
-
-
写出pymysql的cursor.execute()方法中的参数及作用
-
有两个参数, 一个是sql, 一个是args
-
args可以是tuple,对应sql字符串的
%s
-
args也可以是dict, 对应sql字符串的
%(xxx)s
, xxx是dict中的key
-
-
买家秀的模特的所有图片, 图片的名称是姓名-序号, 如'Disen-1.jpg', 'Disen-2.jpg'
-
中国图书网
爬虫所有的小说的基本信息(名称、作者、出版社、原价、折扣价、活动标签、 简介)
-
在Ubuntu 下安装docker
-
基于docker部署ElasticSearch搜索引擎库。
-
基于requests实现索引库及文档的添加和查询。
爬虫第三天
回顾知识点
requests库
-
requests.request(method, url, **kwargs)
常用的参数
-
params/data/json 上传数据
-
files 上传文件
-
headers/cookies
-
proxies 代理服务器
-
auth 授权
-
-
requests.get(url, params, **kwargs)
-
requtests.post(url, data, json, **kwargs)
-
requests.put(url, data, json, **kwargs)
-
requests.delete(url, **kwargs)
-
requests.session() - > session对象, 可以调用 s.get()/post()/put()/delete()等方法,多次请求的会话(连接Session)是同一个
所有的请求返回的对象是requests.Response类的实例, 实例的属性:
-
status_code
-
headers
-
encoding
-
text/content
-
cookies
-
json() 反序列化json文本字符串为python的list或dict的对象
xpath解析
-
路径写法
-
/
依次查找 -
//
间接查找 -
./
从当前元素下查找 -
.//
从当前元素的间接子节点查找
-
-
位置条件
-
//li[1]
整个文档中的第一个<li>
标签 -
//li[last()]
最后一个 -
//li[position() < 3]
前2个 -
//li[position() - 2]
倒数第2个
-
-
属性条件
-
//li[@id="xxxx"]
-
//li[@class=""]
@class 属性名 -
//li[@class="" and @name=""]
多个属性的且的关系
-
-
同时提取两个元素
-
//title/text() | //img/@src
-
-
模糊条件
-
//div[contains(@class, "page")]
查找class属性包含page的所有div标签 -
//div[starts-with(@class, "box")]
第一个class的属性值为box的div标签 -
//div[ends-with(@class, "clearfix")]
最一个class的属性值为clearfix的div标签
-
扩展封装ES-SDK
""" 基于requests库封装操作ElasticSearch搜索引擎的函数 (SDK) """ from urllib.parse import quote import requests INDEX_HOST = '119.3.170.97' INDEX_PORT = 80 class ESIndex(): """ES的索引库的类""" def __init__(self, index_name, doc_type): self.index_name = index_name self.doc_type = doc_type def create(self): # 创建索引库 url = f'http://{INDEX_HOST}:{INDEX_PORT}/{self.index_name}' json_data = { "settings": { "number_of_shards": 5, "number_of_replicas": 1 } } resp = requests.put(url, json=json_data) if resp.status_code == 200: print('创建索引成功') print(resp.json()) def delete(self): # 删除索引库 resp = requests.delete(f'http://{INDEX_HOST}:{INDEX_PORT}/{self.index_name}') if resp.status_code == 200: print('delete index ok') def add_doc(self, item: dict): # 向库中增加文档 doc_id = item.pop('id', None) url = f'http://{INDEX_HOST}:{INDEX_PORT}/{self.index_name}/{self.doc_type}/' if doc_id: url += str(doc_id) resp = requests.post(url, json=item) if resp.status_code == 200: print(f'{url} 文档增加成功!') def remove_doc(self, doc_id): # 删除文档 url = f'http://{INDEX_HOST}:{INDEX_PORT}/{self.index_name}/{self.doc_type}/{doc_id}' resp = requests.delete(url) if resp.status_code == 200: print(f'delete {url} ok') def update_doc(self, item: dict): # 更新文档 doc_id = item.pop('id') url = f'http://{INDEX_HOST}:{INDEX_PORT}/{self.index_name}/{self.doc_type}/{doc_id}' resp = requests.put(url, json=item) assert resp.status_code == 200 print(f'{url} update ok') def query(self, wd=None): # 查询 q = quote(wd) if wd else '' url = f'http://{INDEX_HOST}:{INDEX_PORT}/{self.index_name}/_search?size=100' if q: url += f'&q={q}' resp = requests.get(url) datas = [] if resp.status_code == 200: ret = resp.json() hits = ret['hits']['hits'] if hits: for item in hits: data = item['_source'] data['id'] = item['_id'] datas.append(data) return datas if __name__ == '__main__': index = ESIndex('gushiwen', 'tuijian') # index.create() # index.add_doc({ # 'id': 1, # 'name': 'disen', # 'price': 19.5 # }) # # index.add_doc({ # 'id': 2, # 'name': 'jack', # 'price': 10.5 # }) print(index.query())
正则解析数据
扩展Linux文件权限
100 ->4 -> r 010 -> 2-> w 001 -> 1 -> x 100 | 010 = 110 # 增加权限 110 & 100 == 100 # 验证100权限 110 ^ 100 = 010 # 删除100权限
re面试中的问题
-
compile() /match()/search() 三者之间的区别
-
search()/findall()区别
-
贪婪模式和非贪婪模式
解析站长之家
""" 基于正则re模块解析数据 """ import re import os import requests from utils.header import get_ua base_url = 'http://sc.chinaz.com/tupian/' url = f'{base_url}shuaigetupian.html' headers = { 'User-Agent': get_ua() } if os.path.exists('mn.html'): with open('mn.html', encoding='utf-8') as f: html = f.read() else: resp = requests.get(url, headers=headers) print(resp.encoding) # IOS-8859-1 resp.encoding = 'utf-8' # 可以修改响应的状态码 assert resp.status_code == 200 html = resp.text with open('mn.html', 'w', encoding=resp.encoding) as f: f.write(html) # print(html) # [\u4e00-\u9fa5] compile = re.compile(r'<img src2="(.*?)" alt="(.*?)">') compile2 = re.compile(r'<img alt="(.*?)" src="(.*?)">') imgs = compile.findall(html) # 返回list if len(imgs) == 0: imgs = compile2.findall(html) print(len(imgs), imgs, sep='\n') # 下一页 next_url = re.findall(r'<b>20</b></a><a href="(.*?)" class="nextpage"',html, re.S) print(base_url+next_url[0])
作业
-
写出requests.request()方法常用的参数及参数类型
-
method: str 请求方法, 可以指定 get, post, put, delete, options
-
url : str 请求路径或api接口
-
params/data/json : dict 上传的请求参数及json或form的data数据
-
headers/cookie: dict 请求头或Cookie信息
-
files: dict 上传的文件信息
-
-
写出正则的贪婪模式有哪些
-
.*
0或多个任意字符 -
.+
1或多个任意字符 -
.?
-
.{n, }
至少n个以上的任意字符 -
.{n, m}
至少n个以上的任意字符
-
-
写出str对象的常用方法(10+)
-
join()
-
split()
-
strip()
-
replace()
-
upper()
-
lower()
-
title()
-
index()/rindex()
-
find()/rfind()
-
insert()
-
just()/ljust()/rjust()
-
capitalize() # 每个单词的首字母大写
要求: 自动生成订单号 订单号的格式: 20191226000001 当天的单号按自增,第二天的序号是从1开始。
-
count()
-
encode()
-
startswith()/endswith()
-
format()
-
-
基于Flask实现文件上传服务器, 通过requests测试文件上传接口。
-
优化美女网爬虫,将数据存到es搜索引擎中
-
完成站长之家的多任务爬虫的数据存储(ES引擎/csv)
爬虫第四天
回顾知识点
re正则
-
字符的表示
-
.
任意一个字符, 除了换行 -
[a-f]
范围内的任意一个字符 -
\w
字母、数字和下划线组成的任意的字符 -
\W
-
\d
-
\D
-
\s
-
\S
-
-
量词(数量)表示
-
*
0或多个 -
+
1或多个 -
?
0 或 1 个 -
{n}
n 个 -
{n,}
至少n个 -
{n, m}
n~m个
-
-
分组表示
-
( )
普通的分组表示, 多个正则分组时, search().groups() 返回是元组 -
(?P<name> 字符+数量)
带有名称的分组, 多个正则分组时,search().groupdict()返回是字典, 字典的key即是分组名。import re text = '123abc90ccc' re.search(r'(?P<n1>\d+?)[a-z]+?(?P<n2>\d+)', text).groupdict()
-
-
Python中的正则模块
-
re.compile() 一次生成正则对象,可以多次匹配查询
-
re.match(正则对象, 字符串)
-
re.search()
-
re.findall()
-
re.sub()
re.sub('\d+', '120', text) # 将text中的所有数字替换成120
分享面试题:
给定列表,每一个元组中包含字母和数字, 要求字母和数字分开排序 如: ['abc12', 'abc9', 'abc10', 'ac8', 'ac12'] 排序之后结果是: ['abc9', 'abc10', 'abc12', 'ac8', 'ac12']
def format_number(item): replace_number = re.findall(r'\d+',item)[0].rjust(2, '0') return re.sub(r'\d+',replace_number,item) arr = ['abc12', 'abc9', 'abc10', 'ac8', 'ac12'] sorted(arr, key=format_number)
-
re.split()
-
进程和线程
-
multiprocessing模块(进程)
-
Process 进程类
-
Queue 进程间通信的队列
-
put(item, timeout)
-
item = get(timeout)
-
-
-
threading 模块(线程)
-
Thread 线程类
-
线程间通信(访问对象)
-
queue.Queue 线程队列
-
回调函数(主线程声明, 子线程调用函数)
-
-
BS4数据解析
-
安装包
pip install bs4
-
from bs4 import BeautifulSoup
-
生成bs4根节点对象
root = BeautifulSoup(html, 'lxml')
-
查找节点(bs4.element.Tag)
-
root.find('标签名', class_="", id_="") 返回单节点Tag对象
-
root.find_all('标签名', class_="", id_="", limit=3) 返回limit指定数量的Tag对象的列表
-
root.select('样式选择器')
-
#id
-
.class
-
标签名
-
[属性]
-
div ul
间接子节点, 或div > ul
直接子节点
-
-
-
节点的属性
-
获取文本数据
-
div.text/div.string/div.get_text()
-
-
获取属性
-
div.get('属性名')
-
div['属性名']
-
div.attrs['属性名']
-
div.attrs.get('属性名')
-
-
获取子节点
-
contents 获取所有文本子节点
-
descendants 获取所有子节点对象
-
-
协程爬虫
协程是线程的替代品, 区别在于线程由CPU调度, 协程由用户(程序)自己的调度的。协程需要事件监听模型(事件循环器),它采用IO多路复用原理,在多个协程之间进行调度。
协程的三种方式
-
基于生成器 generator (过渡)
-
yield
-
send()
-
-
Python3 之后引入了 asyncio模块
-
@asyncio.coroutine 协程装饰器, 可以在函数上使用此装饰器,使得函数变成协程对象
-
在协程函数中,可以使用yield from 阻塞当前的协程,将执行的权限移交给 yield from 之后的协程对象。
-
asyncio.get_event_loop() 获取事件循环模型对象, 等待所有的协程对象完成之后结束。
-
-
Python3.5之后,引入两个关键字
-
async 替代 @asyncio.coroutine
-
await 替代 yield from
-
协程第三方的框架
-
gevent
-
eventlet
-
Tornado/Twisted
动态js渲染
Selenium
Selenium是驱动浏览器(chrome, firefox, IE)进行浏览器相关操作(打开url, 点击网页中按钮功连接、输入文本)。
在Python程序中使用时,需要selenium的库和相关浏览的驱动程序(Window, Linux, Mac)。
Splash
Splash 是Web服务, 基于WebKit技术框架,可以动态加载网页。
作业
-
写出生成dict对象的方式有哪些
-
{ }
-
dict([(key, value), ..])
-
json.loads('json格式的字符串')
-
OrderDict
-
dict(zip([ ], [ ]))
-
dict.fromkeys([], value)
-
dict(key=value, key=value)
-
-
写出bs4查找的节点对象的类是什么,它有哪些属性及方法
-
bs4.element.Tag/bs4.Tag 节点对象的类
-
Tag的方法
-
find()
-
find_all()
-
select()
-
get_text()
-
-
Tag的属性
-
string 标签的文本
-
text 标签的文本
-
contents 所有文本的子节点
-
descendants 所有的子节点对象
-
attrs 属性字典
-
-
-
写出创建线程Thread类的实例时的参数有哪些
提示: Thread(参数列表)
-
name 线程名
-
target 线程执行的目标函数
-
args 函数中位置传参, tuple
-
kwargs 指定函数中关键参数传值 , dict
-
-
使用docker搭建Splash服务
-
股票信息提取
-
腾讯公司招聘需求抓取
爬虫最五天
回顾知识点
协程的爬虫
-
协程和线程区别
线程是CPU调度的,多线程是共享同一进程中的内存的(线程本地变量 Local、同步锁Lock、条件变量)。 线程是threading模块
协程是在线程(主)中声明及调度的。协程由用户(程序)调度的,是基于事件模型(IO多路复用模型-select/poll/epoll)。 协程是asyncio模块(Python 3.4+)
-
协程的知识点
-
@asyncio.coroutine 将函数升级为协程对象(闭包函数)
-
yield from 将执行的权限移交给其它协程对象
-
loop = asyncio.get_event_loop() 获取事件模型
-
loop.run_until_complete(协程对象) 事件模型启动协程,直到协程执行完成后,释放事件模型对象。
-
如果是多个协程对象时, 需要使用asyncio.wait() 将多个协程对象以元组方式传入到wait()方法中。
-
-
Python 3.5+增加两个关键字
-
async 替代@asyncio.coroutine
-
await 替代 yield from
注意: async 和 await 必须同时使用
-
-
Seleinum库
-
安装python库
pip install selenium
-
下载浏览器的驱动
-
chrome
-
firefox
-
-
在Python中使用
-
selenium.webdriver.common.by.By
-
By.CLASS_NAME
-
By.CSS_SELECTOR
-
By.ID
-
By.NAME
-
By.TAG_NAME
-
By.XPATH
-
By.LINK_TEXT
-
-
selenium.webdriver.Chrome
-
在实例化Chrome()对象中, 需要指定driver.exe浏览驱动程序的位置。如果位置在环境变量的Path添加了,则不需要指定位置参数。
-
chrome.get(url) 打开url
-
chrome.find_element(by, value) 根据by 查找value的一个元素。
-
chrome.find_elements(by, value) 查找多个元素
-
chrome.window_handlers: list 可以获取窗口标签页
-
chrome.execute_script(js) 当前窗口中执行js脚本
-
chrome.swich_to.window/frame() 切换窗口
-
chrome.close()
-
chrome.page_source 渲染之后的html网页源码
-
-
WebElement 是查找元素的对象类型
-
click() 点击
-
send_keys() 输入内容
-
-
等待WebElement元素出现
-
selenium.webdriver.support 模块
-
-