Requests库
requests.request(method, url, **kwargs)是最基本的方法,其它方法封装内部大多为request
我们通常用r = requests.get(url)获取网页信息,其会构造一个向服务器请求资源的Request对象,对象由Requests库内部生成;get()函数返回的内容表示为r,r是一个Response对象,包含从服务器返回的所有相关资源。
完整方法:requests.get(url, params=None, **kwargs),其中,url为链接,params是字典或字节流格式,**kwargs是12个控制访问的参数。
request参数(使用时写成
r.request.params等):
params:字典或字节序列,作为参数增加到url中data:字典、字节序列或文件对象,作为Request的内容json:JSON格式的数据,作为Request的内容headers:字典,HTTP定制头files:字典类型,传输文件timeout:设定超时时间(单位:秒)proxies:字典类型,设定访问代理服务器,可以增加登录认证allow_redirects:True/False,默认为True,重定向开关stream:True/False,默认为True,获取内容立即下载开关verify:True/False,默认为True,认证SSL证书开关cert:本地SSL证书路径cookies:字典或CookieJar,Request中的cookieauth:元组,支持HTTP认证功能
response对象:
r.status_code:状态码,状态码为200表示访问成功,否则(比如404)表示访问失败。
r.headers:头部信息
r.text:url的页面内容
r.content:url相应内容的二进制形式
r.encoding:从HTTP header中猜测的响应内容编码方式(如果header中不存在charset,则认为编码为ISO-8859-1)
r.apparent_encoding:从内容中分析出的相应内容编码方式(备选方式)(一般更加准确)
r.raise_for_status():如果状态码不是200,则产生异常requests.HTTPError(如404表示失败)
爬取网页的通用代码框架:
import requests
def getHTMLText(url):
try:
r = requests.get(rul, timeout = 30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return "ERROR"
if __name__ = "__main__":
url = "http://www.baidu.com"
print(getHTMLText(url))
HTTP协议
HTTP,Hypertext Transfer Protocol,超文本传输协议
HTTP协议采用URL作为定位网络资源的标识。
URL格式:
http://host[:port][path]
- host:合法的Internet主机域名或IP地址
- port:端口号(默认为80)
- path:资源路径
其它方法:
requests.head():获取HTML网页头信息(可以用r.headers获取头部信息的内容,但是不能使用r.text)
requests.post(url, data = [content]):向HTML网页提交POST请求,附加新的数据
requests.put(url, data = [content]):向HTML网页提交PUT请求,与POST使用类似,不过功能是覆盖原URL位置的资源
requests.patch():向HTML网页提交局部修改请求
requests.delete():向HTML网页提交删除请求
Robots协议:
网站的robots协议一般放在根目录,如http://www.baidu.com/robots.txt
基本语法:
#注释:*表示所有,/表示根目录 User-agent: * (表示限制哪些爬虫) Disallow: / (表示不允许访问的目录)
修改user-agent:
网站可能通过对网站访问的HTTP的头来判断访问是否由爬虫引起,但是我们可以更改头部信息,即修改
r.request.headers(如r = requests.get(url, headers = {'user-agent': 'Mozilla/5.0'}))来进行访问。
搜索引擎关键字接口:
比如:http://www.baidu.com/s?wd=keyword、http://www.so.com/s?q=keyword
我们把信息加在
params里即可:import requests kv = {'wd': 'Python'} kv1 = {'user-agent': 'Mozilla/5.0'} r = requests.get("http://www.baidu.com/s?ie=UTF-8", params = kv, headers = kv1) print(r.request.url)输出的结果:
https://www.baidu.com/s?ie=UTF-8&wd=Python
爬取图片:
import requests import os root = "D://pics/" url = "https://tva4.sinaimg.cn/large/0072Vf1pgy1foenqvqwvqj31hc0xc7aj.jpg" path = root + url.split('/')[-1] #命名为网站上的原文件名,即最后一个'/'的后面的内容 if not os.path.exists(root): os.mkdir(root) if not os.path.exists(path): r = requests.get(url) with open(path, 'wb') as f:#打开文件,定义为标识符f f.write(r.content)##content为二进制内容 f.close() print("Picture Saved Successfully!") else: print("Picture Exists already!")(视频和音频也是一样的)
信息标记和提取
三种信息标记:
XML(eXtensible Markup Language)(用于Internet上的信息交互):
<name ...> ... </name>、<name ... />、<!--...-->JSON(JavaScript Object Notation)(用于移动应用云端和节点的信息通信,无注释):形式为键值对。如果一个键对应多个值,用[]括起来;如果有嵌套,用{}括起来。
(例:
"key": "value"、"key": ["value1", "value2"]、"key": {"subkey": "subvalue"})YMAL(YAML Ain't Markup Language)(用于系统配置文件,易读、有注释):形式为无类型键值对,即
key: value,用缩进表示所属关系,如:name: newname: name1 oldname: name2用
-表示并列关系,如:name: - name1 - name2用
#进行注释,用|表达大段数据。
提取信息的一般方法:
- 完整解析信息的标记形式,再提取关键信息(BeautifulSoup库)
- 直接搜索关键信息(Re库)
Beautiful Soup库
~是解析html和xml文件的功能库。
引用:from bs4 import BeautifulSoup(简写为bs4,导入BeautifulSoup这个类)(注意大写)
解析:soup = BeautifulSoup(r.text, "html.parser")即解析后的内容(会转成UTF-8)
(或者soup2 = BeautifulSoup(open("D://a.html"), "html.parser"))
(soup.prettify()可返回排版后的文件内容)
其它解析器:
lxml的HTML解析器:
BeautifulSoup(mk, 'lxml')lxml的XML解析器:
BeautifulSoup(mk, 'xml')以上两个都需要
pip install lxmlhtml5lib的解析器:BeautifulSoup(mk, 'html5lib')
需要
pip install html5lib
HTML代码是tag组成的树形结构,用<tag>...</tag>括起来。
soup.<tag>可以调用<tag>的内容,如soup.title,可以返回<title>TITLE_CONTENT</title>
如果存在相同名字的tag时,用soup.<tag>只能返回第一个。
用<tag>.parent可以调用上一层tag,<tag>.name可以得到tag名字,如:
soup.a.name(就是a)
soup.a.parent.name、soup.a.parent.parent.name:a的祖先tag的名字
soup.attrs获取tag的属性信息(字典类型)
soup.string表示尖括号之间的内容(类型为bs4.element.NevigableString)
在HTML代码中,<p><!...!></p>表示注释,而我们调用soup.p.string时,会得到注释的内容,而且和上面不同的是,注释的类型是bs4.element.Comment,所以我们可以通过string的类型判断这一段是不是注释。
tag树的遍历:
tag.contents:子节点的列表(也包含字符串节点,比如' '换行酱紫的,用isinstance(tag, bs4.element.Tag)进行判断(需要直接import bs4))
tag.children:子节点的迭代类型
tag.descendants:子孙节点的迭代类型
tag.parent:父节点(如果没有就是None)
tag.parents:祖先节点的迭代类型
tag.next_sibling:按照HTML文本顺序的下一个兄弟节点
tag.previous_sibling:按照HTML文本顺序的上一个兄弟节点
tag.next_siblings:按照HTML文本顺序的后面的所有兄弟节点的迭代类型
tag.previous_siblings:按照HTML文本顺序的前面的所有兄弟节点的迭代类型
tag.find_all(name, attrs, recursive, string, **kwargs):查找,返回列表
name为检索的tag名字;如果要查找多种tag,可以传入一个列表;如果给出的标签名称是True,那么会返回所有标签信息;如果我们要求查找“**开头的tag”,可以利用re库。
attrs限制属性,可以查找属性值,也可以查找键值对,比如:soup.find_all('p', 'xxx')或者soup.find_all(att = 'xxx')。
recursive:是否检索全部子孙,默认为True(False即只检索子节点)。
string指对<>...</>中间区域进行字符串检索(返回的只有中间的字符串的列表)。
简写:tag.find_all(...)可简写作tag(...),soup.find_all(...)也可以简写作soup(...)。
扩展:
<>.find():只返回一个结果
<>.find_parents():在祖先节点中查找,列表类型
<>.find_parent():在祖先节点中查找,只返回一个结果
find_next_siblings()、find_next_sibling()、find_previous_siblings()、find_previous_sibling()同理。
Re库
RE(Regular Expression):正则表达式
正则表达式语法:
.:表示任何字符
[]:字符集,[abc]表示a、b、c;[a-z]表示所有小写字母
[^]:非字符集,[^abc]表示非a、b、c的所有字符
*:前一个字符零次或多次扩展,如abc*表示ab、abc、abcc……
+:前一个字符一次或更多次数的扩展,如abc+表示abc、abcc……
?:前一个字符零次或一次扩展,如abc?表示ab和abc
|:左右表达式任意一个,如abc|def表示abc和def
{m}:前一个字符的m次扩展,ab{2}c表示abbc
{m,n}:前一个字符的m~n次扩展,ab{1,2}c表示abc和abbc
^:匹配字符串开头
$:匹配字符串结尾
():分组标记,内部只能使用|
d:等价于[0-9]
w:等价于[A-Za-z0-9]
应用:
字母组成的字符串:
^[A-Za-z]+$0~255的数字:
([1-9]?d|1d{2}|2[0-4]d|25[0-5])(0-99|100-199|200-249|250-255)
正则表达式的表示类型是raw string(即不包含转义符的字符串),表示为r'text'。
常用函数:
re.search(RawString, String, flags = 0):在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
flags为控制标记,常用标记有:
re.I:忽略大小写re.M:^允许把每行的开头作为匹配的开始位置re.S:.能匹配任意字符(原本不能匹配换行符)
re.match(RawString, String, flags = 0):在一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall(RawString, String, flags = 0):以列表形式返回所有匹配的字符串
re.split(RawString, String, maxsplit = 0, flags = 0):将字符串按正则表达式匹配结果进行分割,将匹配的部分去掉,返回列表(maxsplit表示最大分割数,剩余部分作为最后一个元素输出)
re.finditer(RawString, String, flags = 0):返回一个匹配结果的迭代类型,迭代元素为match对象
re.sub(RawString, repl, String, count = 0, flags = 0):将所有匹配的子串替换,返回替换后的子串(repl表示替换字符串,count表示最大替换次数)match对象的属性:
.string:String.re:RawString.pos:正则表达式搜索文本的开始位置.endpos:正则表达式搜索文本的结束位置match对象的方法:
.group(0):匹配后的字符串(留坑:group(1)、group(2)).start():匹配字符串在原始字符串的开始位置.end():匹配字符串在原始字符串的结束位置span():(.start(), .end())贪婪匹配&最小匹配:
Re库默认采用贪婪匹配,即输出匹配最长的子串。
如果要求得到最短的子串,需要对符号做如下修改:
*?:0次或多次扩展,取匹配的最小次数+?:1次或多次扩展,取匹配的最小次数??:0次或1次扩展,取匹配的最小次数{m, n}?:m次到n次扩展,取匹配的最小次数
两种写法:
- 函数式写法:
rst = re.search(r'...', '...')- 面向对象写法:
pat = re.compile(r'...')rst = pat.search('...')
re.compile(r'...', flags = 0)可以将正则表达式的原生字符串形式编译成re对象,以上六种函数都可以直接用于re对象。
Selenium库
参考:
安装
pip install selenium
在https://chromedriver.storage.googleapis.com/index.html找到对应版本的chromedriver丢到chrome.exe所在文件夹。
(写代码的时候不要把文件命名为selenium.py!会出现ImportError: cannot import name webdriver)
使用
大致框架
- 预备:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome('C:Program FilesGoogleChromeApplicationchromedriver.exe')
selenium.webdriver提供WebDriver的实现,Keys提供案件支持,如RETURN、F1、ALT
如果不给chromedriver.exe配置环境变量,就直接写绝对路径。
- 加载网页:
driver.get("http://www.python.org")
……中间部分搞一些大新闻
- 关闭网页(关闭一个标签页)
driver.close()
交互方式
如果想定位到一个可以输入的文本框,可以先在浏览器中检查网页的elements,找到对应位置的信息。
比如北航CAS登录页面的密码框的信息:
<input type="password" placeholder="请输入密码" i18n="login.form.password.placeholder" id="pwPassword" name="password">
可以这样定位:
elem = driver.find_element_by_id("pwPassword")
其它定位方式:
find_element_by_id
find_element_by_name
find_element_by_xpath #见下
find_element_by_link_text #见下
find_element_by_partial_link_text
find_element_by_tag_name #即查找HTML标签名
find_element_by_class_name #即查找class
find_element_by_css_selector #待填坑
(如果查找多个元素,改成elements即可,返回列表类型)
关于XPATH:
举例:
<html> <body> <form id="loginForm"> <input name="username" type="text" /> <input name="password" type="password" /> <input name="continue" type="submit" value="Login" /> <input name="continue" type="button" value="Clear" /> </form> </body> <html>三种查找form的方法:
login_form = driver.find_element_by_xpath("/html/body/form[1]") #绝对路径 login_form = driver.find_element_by_xpath("//form[1]") #页面中第一个form元素 login_form = driver.find_element_by_xpath("//form[@id='loginForm']") #id为loginForm的form元素三种查找username的方法:
username = driver.find_element_by_xpath("//form[input/@name='username']") #第一个form中name为username的input元素 username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]") #id为loginForm的form元素的第一个input元素 username = driver.find_element_by_xpath("//input[@name='username']") #第一个name属性是username的input元素两种获取Clear按钮的方法:
clear_button = driver.find_element_by_xpath("//input[@name='continue'][@type='button']") #name是continue,type是button的input元素 clear_button = driver.find_element_by_xpath("//form[@id='loginForm']/input[4]") #id是loginForm的form元素的第四个input元素
关于通过链接文本获取超链接:
link = driver.find_element_by_link_text('Content') link = driver.find_element_by_partial_link_text('PartialContent') #部分内容查找
模拟键盘:
elem.clear():将文本框清空
elem.send_keys("xxxxxxx"):输入
elem.send_keys(Keys.RETURN):回车
下拉选择框:
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)
取消选择:
select = Select(driver.find_element_by_id('id'))
select.deselect_all()
点击按钮:
driver.find_element_by_id("submit").click()
弹出对话框:
alert = driver.switch_to_alert()
alert.accept()
alert.dismiss()