python爬虫–总结
前文回顾
python爬虫–类级别写法
python爬虫–爬取9某1看剧网电视剧
python爬虫–爬取网易云音乐评论
python爬虫–scrapy(再探)
python爬虫–scrapy(初识)
python爬虫–selenium模块
python爬虫–异步
文章目录
requests模块中中的content和text的区别
- content用来返回二进制数据,适用于保存二进制数据,例如:图片,视频,文件等
- text适用于显示文本数据,编码根据服务器的响应来显示,也可以自己设置
requests.text是根据网页的响应来猜测编码,如果服务器不指定的话,默认编码是"ISO-8859-1"所以这是为什么有些时候用
response.text 返回的是乱码的原因
IO操作
写文件
open()方法
你必须先用Python内置的open()函数打开一个文件,创建一个file对象,相关的方法才可以调用它进行读写。
f = open('test.txt', 'w',encoding='utf-8')
f.write('Hello, python!')
f.close()
写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()
方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()
的后果是数据可能只写了一部分到磁盘,剩下的丢失了
with open() as 方法
with open('test.txt','w') as f:
f.write('Hello, python!')
读文件
f = open('test.txt','r')
f.read()
f.close()
with open() as 方法
with open('test.txt','r') as f :
print(f.read())
模式 | 描述 |
---|---|
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
创建目录
判断目标
os.path.exists("goal")
判断目标是否存在
创建目录:
os.mkdir("file")
创建目录
举例:
if not os.path.exists('./file'):
os.mkdir('./file')
JSON模块
dump和dumps区别
简单说就是dump需要一个类似于文件指针的参数(并不是真的指针,可称之为类文件对象),可以与文件操作结合,也就是说可以将dict转成str然后存入文件中;而dumps直接给的是str,也就是将字典转成str。
- dump是将对象序列化并保存到文件中
- dumps是将对象序列化
dump函数:
json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
常用参数:
obj
: 表示是要序列化的对象。
fp
: 文件描述符,将序列化的str保存到文件中。json模块总是生成str对象,而不是字节对象;因此,fp.write()
必须支持str输入。
ensure_ascii
: 默认值为True,能将所有传入的非ASCII字符转义输出。如果ensure_ascii
为False,则这些字符将按原样输出。
dumps函数
dumps
函数不需要传文件描述符,其他的参数和dump函数的一样
load和loads反序列化方法,将json格式数据解码为python对象。
json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
fp: 文件描述符,将fp(.read()支持包含JSON文档的文本文件或二进制文件)反序列化为Python对象。
loads函数:
s
: 将s(包含JSON文档的str,bytes或bytearray实例)反序列化为Python对象。
encoding
: 指定一个编码的格式。
loads
也不需要文件描述符,其他参数的含义和load函数的一致。
get请求和post请求
GET产生一个TCP数据包;POST产生两个TCP数据包。
get请求
GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,多个参数用&连接。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)
post请求
POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)
练习:
import requests,json,os
url = 'https://movie.douban.com/j/chart/top_list'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
}
param = {
'type': '5',
'interval_id': '100:90',
'action':'',
'start': '20',
'limit': '20'
}
response = requests.get(url=url,headers=headers,params=param)
data_list = response.json()
if not os.path.exists('./temp'):
os.mkdir('./temp')
fp = open('./temp/douban.json','w',encoding="utf-8")
json.dump(data_list,fp=fp,ensure_ascii=False)
re模块
常用方法
从字符串中寻找指定的字符串
1、match
re.match(pattern, string[, flags])
从首字母开始开始匹配,string如果包含pattern子串,则匹配成功,返回Match对象,失败则返回None,若要完全匹配,pattern要以$结尾,只返回第一个。
2、search
re.search(pattern, string[, flags])
若string中包含pattern子串,则返回Match对象,否则返回None,注意,如果string中存在多个pattern子串,只返回第一个。
3、findall(返回数组)
re.findall(pattern, string[, flags])
返回string中所有与pattern相匹配的全部字串,返回形式为数组。
4、finditer(返回迭代器)
re.findall(pattern, string[, flags])
返回string中所有与pattern相匹配的全部字串,返回形式为数组。
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(localle-aware)匹配 |
re.M | 多行匹配,影响^ $ |
re.S | 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。影响\w,\W,\b,\B |
re.X | 该标志给予更灵活的格式 |
例:
ex = '<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
ex_data = re.findall(ex,gate_text,re.S)
常用元字符
元字符 | 含义 |
---|---|
. |
匹配除换行符以外的任意字符 |
\w |
匹配字母或数字或下划线 |
\s |
匹配任意的空白符 |
\d |
匹配数字 |
\n |
匹配一个换行符 |
\t |
匹配一个制表符 |
^ |
匹配字符串开始 |
$ |
匹配字符串结束 |
\W |
匹配非字母or数字or下标 |
\D |
匹配非数字 |
\S |
匹配非空白符 |
a|b |
匹配字符a或b |
() |
匹配括号内的表达式,也表示一个组 |
[...] |
匹配字符组中的字符 |
[^..] |
匹配除字符组中的字符 |
量词
字符 | 含义 |
---|---|
* |
重复零次或者更多次 |
+ |
重复一次或者更多次 |
? |
重复零次或更多次 |
{n} |
重复n次 |
{n,} |
重复n次或更多次 |
{n,m} |
重复n次到m次 |
贪婪模式和惰性匹配
匹配模式 | 含义 |
---|---|
.* |
贪婪匹配 |
.*? |
惰性匹配 |
#爬取糗事百科图片例子
import re,os,requests
if __name__ == '__main__':
url = 'https://www.qiushibaike.com/imgrank/page/%d/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.478.37'
}
if not os.path.exists("./qiubai"):
os.mkdir("./qiubai")
n = int(input("请输入需要爬取的页数:"))
for pageNum in(1,n):
new_url = format(url%pageNum)
page_text = requests.get(url=new_url,headers=headers).content.decode("utf-8")
ex = '<div class="thumb">.*?<img src="(?P<src>.*?)" alt=.*?</div>'
ex_data = re.finditer(ex,page_text,re.S)
for src in ex_data:
src = "https:"+src.group("src")
img_data = requests.get(url=src,headers=headers).content
img_name = src.split('/')[-1]
img_path = './qiubai/' + img_name
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,"successful!!")
python爬虫利器利器–BeautifulSoup
Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。他是一个工具箱,通过解析文档为用户提供需要抓取的数据。
BeautifulSoup简单操作
from bs4 import Beautifulsoup
#创建Beautiful Soup对象
soup = Beautifulsoup(html)
#也可以使用本地HTML文件来创建对象
soup = Beautifulsoup(open('index.html'))
#打印出soup对象的内容,格式化输出
print(soup.prettify())
BeautifulSoup四大对象种类
BeautifulSoup将负责HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象都可归结为4种:
- Tag
- NavigableString
- BeautifulSoup
- Comment
(1)Tag
Tag就是HTML中的一个个标签
print(soup.title)
#<title>The Dormouse's story</title>
=====================================
print(soup.head)
#<head><title>The Dormouse's story</title></head>
=====================================
print(soup.a)
#<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
=====================================
print(soup.p)
#<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
#验证标签对象的类型
print(type(soup.a))
#<class 'bs4,element.Tag'>
Tag两个重要的属性:name、attrs
print(soup.name)
print(soup.head.name)
#[document]
#head
=====================================
print(soup.pattrs)
#{'class':['title'],'name':'dromouse'}
name:对于其他内部标签,输出的值变为标签本身的名字(soup对象的name为[document])
attrs:列出当前标签的所有属性,得到的类型是一个字典
#如果想要单独获取某个属性
print(soup.p['class'])
print(soup.p.get('class'))
#['title']
(2)NavigablesString
获取标签内部的文字。
print(soup.p.string)
#The Dormouse's story
#验证navigablestring的类型
print(type(soup.pstring))
#<class 'bs4.element.Navigablestring'>
(3)Beautifulsoup
Beautifulsoup对象表示的是一个文档的全部内容。大部分时候,可以把它当做Tag对象,是一个特殊的Tag。
print(type(soup.name))
#<type 'unicode'>
print(soup.name)
#[document]
print(soup.attrs)
#{}空字典
(4)comment
comment对象使用一个特殊类型的Navugablestring对象
遍历文档树
(1)直接子节点
.contents.children属性
.children返回的不是list,不过我们可以通过遍历获取所有子节点。
print(soup.head.children)
#是一个list生成器对象
#<listiterator object at 0x7f71457f5710>
for child in soup.body.children:
print child
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<p class="story">...</p>
(2)所有子孙节点
.descendants属性
.descendants .contents 和 .children 属性仅包含 tag 的直接子节点,.descendants 属性可以对所有 tag 的子孙节点进行递归循环,和 children 类似,我们也需要遍历获取其中的内容
for child in soup.descendants:
print child
运行之后可以发现,是所有节点都被打印出来了。
(3)节点内容
.string 属性
如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容。
如果tag包含了多个子节点,tag就无法确定,string方法应该调用那些子节点的内容,.string的输出结果为None
(4)多个内容
.strings .stripped_strings 属性
.strings 获取多个内容,不过需要遍历获取
for string in soup.strings:
print(repr(string))
# u"The Dormouse's story"
# u'\n\n'
# u"The Dormouse's story"
# u'\n\n'
使用 .stripped_strings 可以去除多余空白内容
for string in soup.stripped_strings:
print(repr(string))
# u"The Dormouse's story"
# u"The Dormouse's story"
# u'Once upon a time there were three little
(5)父节点
.parent 属性
p = soup.p
print p.parent.name
#body
(6)全部父节点
.parents 属性
通过元素的 .parents 属性可以递归得到元素的所有父辈节点
content = soup.head.title.string
for parent in content.parents:
print parent.name
(7)兄弟节点
.next_sibling .previous_sibling 属性
.next_sibling 属性获取了该节点的下一个兄弟节点,.previous_sibling 则与之相反,如果节点不存在,则返回 None 注意:实际文档中的 tag 的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白,因为空白或者换行也可以被视作一个节点,所以得到的结果可能是空白或者换行。
(8)全部兄弟节点
.next_siblings .previous_siblings 属性
通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出
(9)前后节点
.next_element .previous_element 属性
与 .next_sibling .previous_sibling 不同,它并不是针对于兄弟节点,而是在所有节点,不分层次。
(10)所有前后节点
.next_elements .previous_elements 属性
通过 .next_elements 和 .previous_elements 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样
搜索文档树
(1)find_all(name,attrs,recursive,text,**kwargs)
find_all () 方法搜索当前 tag 的所有 tag 子节点,并判断是否符合过滤器的条件
1)name 参数 name 参数可以查找所有名字为 name 的 tag, 字符串对象会被自动忽略掉
-
- A. 传字符串 最简单的过滤器是字符串。在搜索方法中传入一个字符串参数,Beautiful Soup 会查找与字符串完整匹配的内容
soup.find_all('b')
# [<b>The Dormouse's story</b>]
-
- B. 传正则表达式 如果传入正则表达式作为参数,Beautiful Soup 会通过正则表达式的 match () 来匹配内容。下面例子中找出所有以 b 开头的标签,这表示 和标签都应该被找到
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
-
- C. 传列表 如果传入列表参数,Beautiful Soup 会将与列表中任一元素匹配的内容返回。下面代码找到文档中所有标签和标签
soup.find_all(["a", "b"])
# [<b>The Dormouse's story</b>,
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
-
- D. 传 True True 可以匹配任何值,下面代码查找到所有的 tag, 但是不会返回字符串节点
for tag in soup.find_all(True):
print(tag.name)
# html
# head
# title
# body
# p
# b
# p
# a
# a
-
- E. 传方法 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 [4] , 如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False 下面方法校验了当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True
- 2)keyword 参数
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字 tag 的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup 会搜索每个 tag 的”id” 属性.
soup.find_all(id='link2')
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
如果传入 href 参数,Beautiful Soup 会搜索每个 tag 的”href” 属性
soup.find_all(href=re.compile("elsie"))
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
(2)find(name,attrs,recursive,text,**kwargs)
它与 find_all () 方法唯一的区别是 find_all () 方法的返回结果是值包含一个元素的列表,而 find () 方法直接返回结果。
(3)find_parents() find_parent()
find_all () 和 find () 只搜索当前节点的所有子节点,孙子节点等. find_parents () 和 find_parent () 用来搜索当前节点的父辈节点,搜索方法与普通 tag 的搜索方法相同,搜索文档搜索文档包含的内容
python爬虫利器–lxml
lxml用法
首先使用lxml的etree库,然后利用etree.HTML初始化,然后我们将其打印出来。lxml的一个非常实用的功能就是自动修正html代码。
文件读取
处理直接读取字符串,还支持从文件读取内容。
Xpath基本用法
- /:表示的是从根节点开始定位。表示一个层级
- //:表示多个层级。可以表示从任意位置开始定位
- 属性定位://div[@class='song'] tag[@attrName='attrValue']
- 索引定位://div[@class='song']/p[3] 索引从1开始的
- 取文本:
- /text()获取的是标签中直系的文本内容
- //text()标签中非直系的文本内容(所有文本内容)
- 取属性:
/@attrName ==>img/src
(1)获取某个标签的内容
获取a标签的所有内容,a后面就不用再加正斜杠,否则报错。
做法1:
html = etree.HTML(wb_data)
html_data = html.xpath('/html/body/div/ul/li/a')
print(html)
for i in html_data:
print(i.text)
<Element html at 0x12fe4b8>
first item
second item
third item
fourth item
fifth item
做法2:直接在需要查找内容的标签后面加上一个/text()
html = etree.HTML(wb_data)
html_data = html.xpath('/html/body/div/ul/li/a/text()')
print(html)
for i in html_data:
print(i)
<Element html at 0x138e4b8>
first item
second item
third item
fourth item
fifth item
(2)打印指定路径下a标签的属性
html = etree.HTML(wb_data)
html_data = html.xpath('/html/body/div/ul/li/a/@href')
for i in html_data:
print(i)
打印:
link1.html
link2.html
link3.html
link4.html
link5.html
(3)xpath拿到的都是一个个elementTree对象,所以需要查找内容的话,还需要遍历拿到数据的列表。
html = etree.HTML(wb_data)
html_data = html.xpath('/html/body/div/ul/li/a[@href="link2.html"]/text()')
print(html_data)
for i in html_data:
print(i)
打印:
['second item']
second item
python爬虫–验证码,cookie
爬取基于某些用户的用户信息
点击登陆按钮之后发起post请求
post请求中会携带登陆之前录入的相关登陆信息(用户名,密码,验证码。。。)
Cookie:用来让服务器端记录客户端的相关状态
手动处理:
通过抓包工具获取cookie值,将该值封装到headers中
自动处理:
session会话对象
1.可以进行请求的发送
2.如果请求过程中产生了cookie,则cookie会被自动存储/携带在该Session对象中
操作步骤:
1.创建一个session对象:session = requests.Session()
2.使用sess ion对象进行模拟登录post请求的发送( cookie就会被存储在session中)
3.session对象对个人主页对应的get请求进行发送(携带了cookie)
- 框架底层使用JavaScript模拟真实用户对浏览器进行操作。测试脚本执行时,浏览器自动按照脚本代码做出点击,输入,打开,验证等操作,就像真实用户所做的一样,从终端用户的角度测试应用程序。
- 使浏览器兼容性测试自动化成为可能,尽管在不同的浏览器上依然有细微的差别。
- 使用简单,可使用Java,Python等多种语言编写用例脚本。
验证码可以使用云打码,也可以将其下载到本地,人工识别
云打码平台:
- 超级鹰:http://www.chaojiying.com/api-14.html
- feifei:http://www.fateadm.com/
python爬虫–并发
有哪些程序提速的方法
Python对并发编程的支持
- 多线程:threading,利用CPU和IO可以同时执行的原理,让CPU不会干巴巴等待IO完成
- 多进程:multiprocessing,利用多核CPU的能力,真正并行执行任务
- 异步IO:asyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行。
python辅助 - 使用Lock对资源加锁,防止冲突访问
- 使用queue实现不同线程/进程之间的数据通信,实现生产者-消费者模式
- 使用线程池Pool/进程池Pool,简化线程/进程的任务提交、等待结束、获取结果
- 使用subprocess启动外部程序的进程,并进行输入输出交互。
并发相关知识
python并发编程的三种方式:
多线程Thread、多进程Process、多协程Coroutine
1.什么是CPU密集型计算、IO密集型计算?
CPU密集型(CPU-bound):I/O在很短的时间就可以完成,CPU需要大量的计算和处理,特点是CPU占用率相当高。例:压缩解压缩、加密解密、正则表达式搜索。
I/O密集型(I/O bound):文件处理程序、网络爬虫程序、读写数据库程序
2.多线程、多进程、多协程对比
python速度慢的两大原因
动态类型语言:边解释边执行
GIL:无法利用多核CPU并发执行
GIL全局解释器锁
GIL:全局解释器锁(Global Interpreter Lock):是python解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行;即使在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。
python创建多线程
blog_spider.py
import requests
urls = [
f'https://www.cnblogs.com/#p{
page}'
for page in range(1, 51)
]
def craw(url):
res = requests.get(url).text
print(url,len(res))
multi_thread_spider.py
import blog_spider
import threading
import time
def single_spider():
start = time.time()
for url in blog_spider.urls:
blog_spider.craw(url)
end = time.time()
print('single spider time',end-start)
def multi_thread():
start = time.time()
threads = []
for url in blog_spider.urls:
threads.append(
threading.Thread(target=blog_spider.craw,args=(url,))
)
for thread in threads:
thread.start()
for thread in threads:
thread.join()
end = time.time()
print('multi spider time', end - start)
if __name__ == '__main__':
single_spider()
multi_thread()
python爬虫利器–selenium
Selenium(浏览器自动化测试框架)是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。
Selenium优点:
Selenium的调用
from selenium import webdriver
## 如果是chrome浏览器的驱动
driver=webdriver.Chrome("G:\Anaconda3-5.3.0\chromedriver.exe")
## 如果是chrome浏览器的驱动
driver=webdriver.Chrome()
Selenium的使用
定位
8种定位方式
- id
- name
- class name
- tag name
- link text
- partial link text
- xpath
- css selector
定位元素的使用
定位一个元素 | 定位多个元素 | 含义 |
---|---|---|
find_element_by_id | find_elements_by_id | 通过元素id定位 |
find_element_by_name | find_elements_by_name | 通过元素name定位 |
find_element_by_class_name | find_elements_by_class_name | 通过classname定位 |
find_element_by_tag_name | find_elements_by_tag_name | 通过标签定位 |
find_element_by_link_text | find_elements_by_link_text | 通过完整超链接定位 |
find_element_by_partial_link_text | find_elements_by_partial_link_text | 通过部分链接定位 |
find_element_by_css_selector | find_elements_by_css_selector | 通过css选择器定位 |
find_element_by_xpath | find_elements_by_xpath | 通过xpath表达式定位 |
Webdriver模块的使用
方法 | 说明 |
---|---|
set_window_size() | 设置浏览器的大小 |
back() | 控制浏览器后退 |
forward() | 控制浏览器前进 |
refresh() | 刷新当前页面 |
clear() | 清除文本 |
send_keys (value) | 模拟按键输入 |
click() | 单击元素 |
submit() | 用于提交表单 |
get_attribute(name) | 获取元素属性值 |
is_displayed() | 设置该元素是否用户可见 |
size | 返回元素的尺寸 |
text | 获取元素的文本 |
#编写基于浏览器自动化的操作代码
- 发起请求: get(url)
- 标签定位: find系列的方法
- 标签交互: send_ keys( 'xxx' )
- 执行js程序: excute_script('jsCod')
- 前进,后退: back(),forward( )
- 关闭浏览器: quit()
selenium处理iframe
iframe 元素会创建包含另外一个文档的内联框架
- 如果定位的标签存在于iframe标签之中,则必须使用switch_to.frame(id)
- 动作链(拖动) : from selenium.webdriver import ActionChains
- 实例化一个动作链对象: action = ActionChains (bro)
- click_and_hold(div) :长按且点击操作
- move_by_offset(x,y)
- perform( )让动作链立即执行
- action.release( )释放动作链对象
selenium无头浏览器+规避检测
from selenium import webdriver
from time import sleep
#实现无可视化界面
from selenium.webdriver.chrome.options import Options
#实现规避检测
from selenium.webdriver import ChromeOptions
#实现无可视化界面
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
#实现规避检测
option = ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
bro = webdriver.Chrome(executable_path=r"E:\google\Chrome\Application\chromedriver.exe",chrome_options=chrome_options,options=option)
bro.get('https://www.baidu.com')
print(bro.page_source)
sleep(2)
bro.quit()
python爬虫利器–scrapy框架
为什么要使用scrapy?
- 它更容易构建和大规模的抓取项目
- 它内置的机制被称为选择器,用于从网站(网页)上提取数据
- 它异步处理请求, 速度十分快
- 它可以使用自动调节机制自动调整爬行速度
- 确保开发人员可访问性
scrapy的优点
- Scrapy很容易扩展,快速和功能强大;
- 这是一个跨平台应用程序框架(在Windows , Linux , Mac OS和BSD )。
- Scrapy请求调度和异步处理;
- Scrapy附带了一个名为Scrapyd的内置服务 ,它允许使用JSON Web服务.上传项目和控制蜘蛛。
- 也能够刮削任何网站,即使该网站不具有原始数据访问API ;
1.核心架构
一个整体的scrapy包含以下结构:
(1)scrapy Engine(引擎):负责调度信号与数据在各个组件间的传递,它就是框架的核心。
(2)scrapy Scheduler(爬虫调度器):调度等待爬取的网址的顺序(优先级)
(3)Downloader Middlewares (下载中间件):在引擎与下载器中间进行一系列处理,包括设置代理,请求头等
(4)Downloader(下载器):将下载网址的响应返回给引擎,引擎再返回给爬虫
(5)Spider Middlewares(爬虫中间件):对引擎和爬虫之间的通信进行处理
(6)Spider(爬虫):对响应response进行处理,提取出所需的数据(可存入items),也可以提取出接下来要爬取的网址
(7)Item Popline(实体管道):接收从爬虫中提取出来的item,并对item进行处理(清洗、验证、存储到数据库等)
2.执行流程
The data flow in Scrapy is controlled by the execution engine, and goes like this:
- The Engine gets the initial Requests to crawl from the Spider.
- The Engine schedules the Requests in the Scheduler and asks for the
next Requests to crawl. - The Scheduler returns the next Requests to the Engine.
- The Engine sends the Requests to the Downloader, passing through the Downloader Middlewares (see process_request()).
- Once the page finishes downloading the Downloader generates a Response (with that page) and sends it to the Engine, passing through the Downloader Middlewares (see process_response()).
- The Engine receives the Response from the Downloader and sends it to the Spider for processing, passing through the Spider Middleware (see process_spider_input()).
- The Spider processes the Response and returns scraped items and new Requests (to follow) to the Engine, passing through the Spider Middleware (see process_spider_output()).
- The Engine sends processed items to Item Pipelines, then send processed Requests to the Scheduler and asks for possible next Requests to crawl.
- The process repeats (from step 1) until there are no more requests from the Scheduler.
所有数据的传输都是由引擎来调控执行的
1,首先通过爬虫传递最初始requests给引擎
2,引擎传递requests给调度器,并询问下一个requests
3,调度程序把所有经过排序的requests返回给引擎
4,引擎依次将requests传递给下载器(可经过下载中间件处理,也可不处理)
5,当页面完成下载,下载器得到响应response,将response传给引擎
6,引擎接收到response后经过爬虫中间件(也可不经过)传递给爬虫
7,将所需的Items原路返回到Engine
8,Engine将Items发送到ItemPipeline(可以是本地,可以是数据库),完成一次循环,并请求下一次循环
9,从第一步开始,直到调度器没有requests请求时结束!
Scrapy基本使用
1.使用命令行创建scrapy项目工程scrapy startproject qiushi
就会提示你创建成功。
2.cd到该目录下,并且创建first spider
文件说明
名称 | 作用 |
---|---|
scrapy.cfg | 项目的配置信息,主要为scrapy命令行工具提供一个基础的配置信息(真正爬虫相关的配置信息在settings.py文件中) |
items.py | 设置数据存储模板,用于结构化数据 |
pipelines | 数据处理行为,如:一般结构化的数据持久化 |
settings.py | 配置文件,如:递归的层数,并发数,延迟下载等 |
spiders | 爬虫目录,如:创建文件,编写爬虫规则 |
item pipeline主要作用:
- 清理html数据
- 验证爬取的数据
- 去重并丢弃
- 将爬取的结果保存到数据库中
Settings常用配置
终端命令:scrapy crawl qiubai -o qiushi.csv
需注意的是:基于终端命令存储,只能存储(‘json’, ‘jsonlines’, ‘jl’, ‘csv’, ‘xml’,
‘marshal’, ‘pickle’)后缀的名称
基于管道的持久化存储
- 数据解析
- 在item类中定义相关的属性
- 将解析的数据封装存储到item类型的对象
- 将item类型的对象提交给管道进行持久化存储的操作
- 在管道类的process_ item中要将其接受到的item对象中存储的数据进行持久化存储操作
- 在配置文件中开启管道
python爬虫面试题
什么是爬虫?网页爬取的流程是怎么样的?
爬虫就是模拟客户端发送网络请求,接收请求响应的一种按照一定规则自动的抓取互联网信息的程序。
主要流程:构建url,发送请求获取响应,提取数据和数据入库等操作。
2.python爬虫常用的第三方库?
requests,beautifulSoup,etree,Xpath,scrapy,selenium,json。
3.什么是URL?
url是统一资源定位符。
4.在数据抓取的过程中GET和POST方法有什么区别?
- GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL 的编码格式采用的是 ASCII 编码,而不是unicode,即是说所有的非 ASCII 字符都要编码之后再传输。
- POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。
2.传输数据的大小,GET附加在URL中,一般URL的长度是有限制的。POST传输的数据大小是没有限制的。
3.安全性
POST安全性比GET高。在进行登录操作,通过 GET 请求,用户名和密码都会暴露再 URL 上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了
5.对Selenium的了解
selenium是Web自动化测试工具,可以根据我们的指令,让浏览器自动加载页面,获取所需要的数据,或者页面截屏。selenium自己不带浏览器,他需要与第三方浏览器结合在一起才能使用。
6.常见的反爬虫和应对方法?
(1)通过Headers反爬虫
referer:告诉符务器该网页是从哪个页面链接过来的
从用户请求的 Headers 反爬虫是最常见的反爬虫策略。很多网站都会对 Headers 的 User-Agent 进行检测,还有一部分网站会对 Referer进行检测(一些资源网站的防盗链就是检测 Referer)。如果遇到了这类反爬虫机制,可以直接在爬虫中添加Headers,将浏览器的User-Agent 复制到爬虫的 Headers 中;或者将 Referer 值修改为目标网站域名。对于检测 Headers 的反爬虫,在爬虫中修改或者添加Headers 就能很好的绕过。
(2)基于用户行为反爬虫
通过检测用户行为,例如统一IP短时间多次访问同一页面,或者同一账户短时间内多次进行相同操作。使用代理IP
(3)动态页面的反爬虫
有些时候需要爬取的数据是通过ajax请求得到的。分析出具体的参数和响应的具体含义,使用requests进行分析得到需要的数据。有些是有还是加密的,可以使用JS逆向。或者使用selenium获取数据。
7.简单说一下你对scrapy的了解
scrapy主要有五大核心组件,引擎,url调度器,下载器,爬虫器,项目管道。
封装起来的框架,使用的异步处理,相比于自己编写的爬虫脚本来说,运行速度快。
scrapy 框架运行的机制?
(1)从 start_urls 里获取第一批 url 并发送请求,请求由引擎交给调度器入请求队列,获取完毕后,调度器将请求队列里的请求交给下载器去获取请求对应的响应资源,并将响应交给自己编写的解析方法做提取处理:1. 如果提取出需要的数据,则交给管道文件处理;
(2)如果提取出 url,则继续执行之前的步骤(发送 url 请求,并由引擎将请求交给调度器入队列…),直到请求队列里没有请求,程序结束。
终端命令;
创建项目文件:scrapy startproject myproname
创建爬虫文件:scrapy genspider example www.example.com
运行项目文件:scrapy crawl example