python爬虫笔记
爬虫
http://httpbin.org/ 验证请求
1.urllib库(python3)
python内置的HTTP请求库
urllib.request 请求模块 (https://yiyibooks.cn/xx/python_352/library/urllib.request.html#module-urllib.request)
urllib.error 异常处理模块(https://yiyibooks.cn/xx/python_352/library/urllib.error.html#module-urllib.error)
urllib.parse url解析模块(https://yiyibooks.cn/xx/python_352/library/urllib.parse.html#module-urllib.parse)
urllib.robotparser robots.txt解析模块(https://yiyibooks.cn/xx/python_352/library/urllib.robotparser.html#module-urllib.robotparser)
请求:
import urllib.request
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
- url 请求的网址
- data 加上以post请求发送,不加以get请求发送
- [timeout, ]* 设置请求时间 超过时间报TIME OUT异常
- cafile
- capath
- cadefault
- context
响应
import urllib.request response = urllib.request.urlopen('https://www.python.org') print(type(response))#响应类型 print(response.status)#状态码 print(response.getheaders())#响应头 返回元组组成的列表 print(response.getheader('Server'))#获取特定的响应头 print(response.read().decode('utf-8'))#获得响应体
也可以根据请求来获得响应
from urllib import request, parse url = 'http://httpbin.org/post' headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Host': 'httpbin.org' } dict = { 'name': 'Germey' } data = bytes(parse.urlencode(dict), encoding='utf8') req = request.Request(url=url, data=data, headers=headers, method='POST') response = request.urlopen(req) print(response.read().decode('utf-8'))
Handler
代理ip
proxy_handler = urllib.request.ProxyHandler({ 'http': 'http://127.0.0.1:9743', 'https': 'https://127.0.0.1:9743' }) opener = urllib.request.build_opener(proxy_handler) response = opener.open('http://httpbin.org/get') print(response.read())
cookie(保持登录会话信息)
import http.cookiejar, urllib.request cookie = http.cookiejar.CookieJar()#也可以修改CookieJar把cookie保存到本地文件(MozillaCookieJar或LWPCookieJar) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') for item in cookie: print(item.name+"="+item.value)
异常
from urllib import request, error try: response = request.urlopen('http://bubaidu.com/index.htm') except error.HTTPError as e: print(e.reason, e.code, e.headers, sep='\n') except error.URLError as e: print(e.reason) else: print('Request Successfully')
url解析
urlparse
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)#urlstring:请求地址,scheme:约束 协议,allow_fragments:将fragment拼接到前面有数据的
from urllib.parse import urlparse result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', scheme='https',allow_fragments=False) print(type(result),result) --------------------------------------------------------------------- <class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5#comment', fragment='')
urlunparse(将url和参数请求等进行拼接)
urljoin(将两个url进行拼接,以后面的为基准)
urlencode(将字典拼接为url的请求参数)
=============================================================================================
2.requests库
(request库在urllib3的基础上进行加强,推荐使用request库)
pip install requests
import requests response = requests.get('https://www.baidu.com/') print(type(response)) print(response.status_code)#响应状态码 print(type(response.text)) print(response.text)#响应体 print(response.cookies)#cookies
请求
get请求
requests.get(url, params=None, **kwargs)#params以字典形式添加请求参数,也可以直接在url中写参数
#可以添加headers(有些网址不添加headers会报500的错误)
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
response = requests.get("https://www.zhihu.com/explore", headers=headers)
解析json
import requests import json response = requests.get("http://httpbin.org/get") print(type(response.text)) print(response.json()) print(json.loads(response.text))#用json转码,结果和response.json()返回结果一样 print(type(response.json()))
获取二进制数据(用于下载图片等)
import requests response = requests.get("https://github.com/favicon.ico") with open('favicon.ico', 'wb') as f:#将图片保存到本地 f.write(response.content)#获得图片的二进制内容并写入 f.close()
基本post请求
import requests data = {'name': 'germey', 'age': '22'} headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36' } response = requests.post("http://httpbin.org/post", data=data, headers=headers) print(response.json())
响应
response = requests.get('http://www.jianshu.com') print(type(response.status_code), response.status_code)#状态码 print(type(response.headers), response.headers)#响应头(字典) print(type(response.cookies), response.cookies)#cookies(列表) print(type(response.url), response.url) # print(type(response.history), response.history)#访问的历史记录
文件上传
files = {'file': open('favicon.ico', 'rb')} response = requests.post("http://httpbin.org/post", files=files) print(response.text)
会话维持(模拟登陆)
s = requests.Session() s.get('http://httpbin.org/cookies/set/number/123456789') response = s.get('http://httpbin.org/cookies') print(response.text)
证书验证(在以https协议请求时,会先检测ssl是否是合法的)
import requests from requests.packages import urllib3 urllib3.disable_warnings() response = requests.get('https://www.12306.cn', verify=False) print(response.status_code)
代理
proxies = { "http": "http://127.0.0.1:9743", "https": "https://127.0.0.1:9743", } response = requests.get("https://www.taobao.com", proxies=proxies) print(response.status_code)
也可以使用socks代理(pip3 install 'requests[socks]')
proxies = { 'http': 'socks5://127.0.0.1:9742', 'https': 'socks5://127.0.0.1:9742' }
超时设置
response = requests.get("http://httpbin.org/get", timeout = 0.5)
登录验证设置
r = requests.get('http://120.27.34.24:9001', auth=('user', '123')) print(r.status_code)
异常处理
import requests from requests.exceptions import ReadTimeout, ConnectionError, RequestException try: response = requests.get("http://httpbin.org/get", timeout = 0.5) print(response.status_code) except ReadTimeout: print('Timeout') except ConnectionError: print('Connection error') except RequestException: print('Error')
===================================================================================================================
3.BeautifulSoup库
pip install BeautifulSoup4
解析库
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, "html.parser") | Python的内置标准库、执行速度适中 、文档容错能力强 | Python 2.7.3 or 3.2.2)前的版本中文容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快、文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, "xml") | 速度快、唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档 | 速度慢、不依赖外部扩展 |
基本使用
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.prettify())#格式化,补全代码 print(soup.title.string)#输出title标签中的内容
print(soup.title)#获取titile标签及其包裹的内容 print(soup.title.name)#获取名称 结果为title print(soup.p.attrs['name'])#获取属性字段为的name的值 print(soup.p['name'])#获取获取属性字段为的name的值 print(soup.p.string)#获取p标签中的内容
也可以嵌套选择
print(soup.head.title.string)
获得子节点和子孙节点方法
#获得p标签子节点 soup.p.contents#列表 soup.p.children#迭代器 #获得p标签所有子孙节点 soup.p.descendants#迭代器
例:
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.p.children) for i, child in enumerate(soup.p.children): print(i, child)
获得父节点和祖先节点
soup.a.parent#获取a标签的父节点 soup.a.parents#获取a标签的祖先节点(迭代器)
获取兄弟节点
soup.a.next_siblings#获取a标签后面的兄弟节点(迭代器) soup.a.previous_siblings#获取a标签前面的兄弟节点(迭代器)
标准选择器
find_all( name , attrs , recursive , text , **kwargs )#可根据标签名、属性、内容查找文档
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.find_all('ul'))#获取ul标签及内容,返回结果为列表 print(soup.find_all(attrs={'id': 'list-1'}))#获取id为list-1的标签体,返回结果为列表 print(soup.find_all(id='list-1'))#特殊的字段可以用这种形式,获取id为list-1的标签体,返回结果为列表 print(soup.find_all(class_='element'))#class比较特殊 print(soup.find_all(text='Foo'))#返回的结果:内容为Foo的元组 例['Foo', 'Foo'] (多用于匹配内容)
find( name , attrs , recursive , text , **kwargs )#find返回单个元素,find_all返回所有元素
find_parents()#返回所有祖先节点 find_parent()# 返回直接父节点。 find_next_siblings()#返回后面所有兄弟节点 find_next_sibling()#返回后面第一个兄弟节点。 find_previous_siblings()#返回前面所有兄弟节点 find_previous_sibling()#返回前面第一个兄弟节点。 find_all_next()#返回节点后所有符合条件的节点 find_next()#返回第一个符合条件的节点 find_all_previous()#返回节点后所有符合条件的节点 find_previous()#返回第一个符合条件的节点
CSS选择器
通过select()直接传入CSS选择器即可完成选择
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.select('.panel .panel-heading')) print(soup.select('ul li')) print(soup.select('#list-2 .element')) print(type(soup.select('ul')[0]))
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') for ul in soup.select('ul'): print(ul['id']) print(ul.attrs['id'])
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') for li in soup.select('li'): print(li.get_text())
总结
- 推荐使用lxml解析库,必要时使用html.parser
- 标签选择筛选功能弱但是速度快
- 建议使用find()、find_all() 查询匹配单个结果或者多个结果
- 如果对CSS选择器熟悉建议使用select()
- 记住常用的获取属性和文本值的方法
===================================================================================================================================
4.pyquery库
(pyquery比BeautifulSoup更加简易,熟悉jquery推荐使用pyquery)
from pyquery import PyQuery as pq doc = pq(html) print(doc('li'))#打印所有li标签及内容(css选择器)
URL初始化
doc = pq(url='http://www.baidu.com')#将网页html代码作为参数
文件初始化
doc = pq(filename='demo.html')#这样写文件和代码在同一路径
基本CSS选择器
from pyquery import PyQuery as pq doc = pq(html) print(doc('#container .list li'))
from pyquery import PyQuery as pq doc = pq(html) items = doc('.list') #查找元素 lis = items.find('li')#查找子元素为li标签的 lis2 = items.children('.active')#查找所有的直接子元素class为active的 container = items.parent()#获取直接父元素 parents = items.parents()#获取父节点及所有祖先节点,也可以添加选择器 li = doc('.list .item-0.active')#.item-0.active表示一个整体 例:class="item-0 active" print(li.siblings())#获取所有的兄弟节点
遍历
from pyquery import PyQuery as pq doc = pq(html)#如果doc('li')获得为一个值则可以直接操作,如果多个可以进行遍历 lis = doc('li').items()#转换为generator类型 print(type(lis)) for li in lis: print(li)
获取信息
from pyquery import PyQuery as pq doc = pq(html) a = doc('.item-0.active a') print(a.attr('href'))#获取属性为href的值 print(a.attr.href)#获取属性为href的值 print(a.text())#获取文本 print(a.html())#获取HTML
DOM操作
from pyquery import PyQuery as pq doc = pq(html) li = doc('.item-0.active') #addClass、removeClass li.removeClass('active')#移除active属性 li.addClass('active')#添加active属性 #attr、css li.attr('name', 'link')#修改name属性的值(没有则添加,有则修改) li.css('font-size', '14px')#添加style属性并添加css样式 #remove html = ''' <div class="wrap"> Hello, World <p>This is a paragraph.</p> </div> ''' doc = pq(html) wrap = doc('.wrap') print(wrap.text())#Hello, World
This is a paragraph. wrap.find('p').remove()#移除 print(wrap.text())#Hello, World
其他DOM方法