目录
一、链式调用
在python中实现链式调用只需在函数返回对象自己就行了。
1 class Person:
2 def name(self, name):
3 self.name = name
4 return self
5
6 def age(self, age):
7 self.age = age
8 return self
9
10 def show(self):
11 print "My name is", self.name, "and I am", self.age, "years old."
12
13 p = Person()
14 p.name("Li Lei").age(15).show()
二、beautifulsoup
2.1介绍
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4
#安装 Beautiful Soup
pip install beautifulsoup4
#安装解析器
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:
$ apt-get install Python-lxml
$ easy_install lxml
$ pip install lxml
另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:
$ apt-get install Python-html5lib
$ easy_install html5lib
$ pip install html5lib
下表列出了主要的解析器,以及它们的优缺点,官网推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, "html.parser") |
Python的内置标准库执行速度适中文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, "lxml") |
速度快文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, ["lxml", "xml"])``BeautifulSoup(markup, "xml") |
速度快唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, "html5lib") |
最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 | 速度慢不依赖外部扩展 |
中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
2.2 基本使用
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
#基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml') #具有容错功能
res=soup.prettify() #处理好缩进,结构化显示
print(res)
2.3遍历文档树
每一个BeautifulSoup 的对象的标签都可以看成一个个对象,标签的属性可以看成对象的属性,通过遍历、查找文档树查找到的标签依然可以看成一个对象。
#遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
#1、用法
#2、获取标签的名称
#3、获取标签的属性
#4、获取标签的内容
# 必须掌握的
head=soup.head
print(head)
p=soup.p
print(p)
p=soup.body.p
print(p)
# 获取p标签的名字
p=soup.body.p
print(p.name)
# 获取属性
# 当你获取class的时候,获取的是个列表?class可以有多个
p=soup.body.p
print(p['class'])
print(p['id'])
print(p.attrs.get('class'))此方法与上面的方法相同
# 获取内容
# text:获取所有的文字,包括子标签(笔记多),爬去文章时可以直接获取文章内容div的text就能取出文章内的所有文字
# string:获取当前第一级目录的文字,如果嵌套多层,就取不出文字
# strings:生成器,每一层的文字都放在里面
p=soup.body.p
print(p.text)
print(p.string)
print(list(p.strings))
# 用的比较少(了解)
#5、嵌套选择
print(soup.head.title.string)
print(soup.body.a.string)
#6、子节点、子孙节点
print(soup.body.p.contents)
print(list(soup.body.p.children))
print(list(soup.body.p.descendants)) #子子孙孙
#7、父节点、祖先节点
print(soup.body.p.parent) #直接父节点
print(list(soup.body.p.parents)) # 父亲,父亲的父亲。。。全都放到生成器中
#8、兄弟节点
print(soup.a.next_sibling) #下一个兄弟
print(soup.a.previous_sibling) #上一个兄弟
2.4 搜索文档树
Beautiful Soup定义了很多搜索方法,这里着重介绍2个:find()
和 find_all()
。其它方法的参数和用法类似,请读者举一反三。
find_all( name , attrs , recursive , text , **kwargs )、find( name , attrs , recursive , text , **kwargs )
find_all找出所有满足条件的标签,如果有多个就放在列表中;find找出满足条件的第一个标签,就算有多个也只找第一个,具体使用方法如下:
# p是标签对象,跟soup是一样的
# p=soup.find(name='p',class_='story')
# print(p)
# b=soup.find(name='b')
# print(b)
# 通过属性查找方式一
# b=soup.find(id='id_b')
# print(b)
# 通过属性查找的方式二
# b=soup.find(attrs={'id':'id_b'})
# p=soup.find(attrs={'class':'story'})
# print(p)
# 列表查找
# ret=soup.find_all(name=['p','b'])
# ret=soup.find_all(id=['id_b','link1'])
# print(ret)
# 正则
# import re
# # 查找名字以b开头的标签
# # ret=soup.find_all(name=re.compile('^b'))
# ret=soup.find_all(id=re.compile('^l'))
# print(ret)
# True
# 查找所有有id的标签
# ret=soup.find_all(id=True)
# ret=soup.find_all(name=True)
# print(ret)
# 方法
# def has_class_but_no_id(tag):
# return tag.has_attr('class') and not tag.has_attr('id')
# ret=soup.find_all(has_class_but_no_id)
# print(ret)
# 取属性,取文字
# tag对象['src'] tag对象.attrs.get('src')
# tag对象.text string
# 遍历文档树和搜索文档树可以同时用
# soup.body.find(name='p').b
# soup.body.find(name='p').find()
# print(type(soup))
# #Tag对象用起来跟BeautifulSoup对象用起来完全一样
# body=soup.body
# print(type(body))
# 拓展 链式调用(跟语言没关系,jq)
# 链式调用在python中如何实现?点多少次,其实还是对象本身
# class A:
# def test(self,name):
# self.name=name
# return self
# def test2(self,age):
# self.age=age
# return self
# a=A()
# a.test('lqz').test2(19)
# print(a.age)
# bs4 其他用法
#limit 限制查找的个数
# ret=soup.find_all(name='p',limit=1)
# print(ret)
# soup.find_all()
# recursive 是否递归查找
# ret=soup.body.find_all(name='p',recursive=False)
# ret2=soup.body.find_all(name='p',recursive=True)
# print(len(ret))
# print(len(ret2))
2.5修改文档树
Beautiful Soup的强项是文档树的搜索,但同时也可以方便的修改文档树,具体使用方法参见Beautiful Soup 4.2.0 文档
链接:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id40
2.6总结
# 总结:
#1、推荐使用lxml解析库
#2、三种选择器:标签选择器,find与find_all,css选择器
1、标签选择器筛选功能弱,但是速度快
2、建议使用find,find_all查询匹配单个结果或者多个结果
3、如果对css选择器非常熟悉建议使用select
#3、记住常用的获取属性attrs和文本值get_text()的方法
2.7实例:爬取小说三国演义
import requests,re,os
from bs4 import BeautifulSoup
ret = requests.get('http://www.shicimingju.com/book/sanguoyanyi.html')
# print(ret.text)
soup = BeautifulSoup(ret.text,'lxml')
mulu_li = soup.find(name='div',class_='book-mulu')
# print(mulu_li)
ret1 = soup.select('.book-mulu>ul>li')
#http://www.shicimingju.com/book/sanguoyanyi/1.html
content_str = ''
if not os.path.isdir('三国演义'):
os.mkdir('三国演义')
#分章节下载
for i in ret1:
# print(i.text)
name = i.text
url = 'http://www.shicimingju.com' + i.find(name='a')['href']
# print(url)
ret2 = requests.get(url)
soup = BeautifulSoup(ret2.text, 'lxml')
div = soup.find(name='div', class_="card bookmark-list")
content = div.text
head = div.find(name='h1').text
with open(f'三国演义/{head}.md','wt',encoding='utf-8') as f:
f.write(content)
#统一下载到一个文件
# for i in ret1:
# # print(i.text)
# name = i.text
# url = 'http://www.shicimingju.com' + i.find(name='a')['href']
# # print(url)
# ret2 = requests.get(url)
# soup = BeautifulSoup(ret2.text, 'lxml')
# div = soup.find(name='div', class_="card bookmark-list")
# content_str += div.text
# with open('三国演义/三国演义.md','wt',encoding='utf-8') as f:
# f.write(content_str)
# f.flush()
# print('下载完成')
# print(content_str)
# head = div.find(name='h1').text
# with open(f'三国演义/{head}.md','wt',encoding='utf-8') as f:
# f.write(content)
# print(content)
2.8实例:爬取盗墓笔记
#爬盗墓笔记
ret = requests.get('http://www.dmbj.cc/')
ret.encoding = 'utf-8'
# print(ret.text)
soup = BeautifulSoup(ret.text,'lxml')
li_list = soup.find_all(name='li',class_='pop-book')
for i in li_list:
book_name1 = i.text.strip()
# print(book_name1)
book_name = book_name1.strip('\n南派三叔')
print(book_name)
book_url = i.find(name='a')['href']
ret2 = requests.get(book_url)
ret2.encoding = 'utf-8'
soup2 = BeautifulSoup(ret2.text, 'lxml')
# print(ret2)
content_div = soup2.find(name='div',class_="xsbox clearfix")
url = content_div.find_all(name='a')
if not os.path.isdir(f'{book_name}'):
os.mkdir(f'{book_name}')
# print(content_div)
for j in url:
# print(j.text)
content_url = j['href']
content_name = j.text
if content_name[-1] == '?':
content_name = content_name.strip('?')
ret3 = requests.get(content_url)
ret3.encoding = 'utf-8'
soup3 = BeautifulSoup(ret3.text, 'lxml')
content = soup3.find(name='div',class_="m-post").text
with open(f'{book_name}/{content_name}.txt', 'wt', encoding='utf-8') as f:
f.write(content)
# print(content)
三、ip代理池(收费代理、免费代理)
ip代理池就是一个存放有很多ip的数据库,当我们请求这个数据库接口时可以得到一个由接口随机返回的ip和端口,我们可以使用这些ip作为我们的ip去向某个网站发送请求,这样可以防止服务端因为我们请求次数过多而封我们的ip。
#代理的使用方法,proxies内是我们的代理ip
ret=requests.get('http://101.133.225.166:8088/',
proxies={'http':'222.95.241.88:3000'}
)
在访问某些需要校验cookie的服务端时,只有IP代理池还不够,我们需要做一个cookie池,每次向服务器发送请求时的ip和cookie都是随机组合的,这样服务端就会以为这些请求是不同的用户发出的,从而使我们在爬虫的时候不会被封ip。
3.1收费代理池
收费代理池一般是第三方做的ip代理网站,如:http://www.goubanjia.com/
3.2免费代理池
我们可以从网上爬取一些免费的代理ip自己做代理池,步骤:自己搭建:flask框架搭建服务,后台用爬虫(requests爬取免费),放入redis。
当然,我们还可以使用GitHub上开源的个人代理池项目,这时别人写好的项目,我们只需要部署到自己的服务器上就可以使用。自己爬的代理ip需要我们定时对这些ip进行测试,保证ip是可用的,测试方式:用这些ip向某个网站发送请求,如果有响应就可以使用。
#1 下载下来,打开
#2 安装依赖 pip3 install -r requirements.txt
#3 修改配置文件Config/setting.py
35行左右,意思是爬取的代理放到redis中,
DB_TYPE = getenv('db_type', 'redis').upper()
DB_HOST = getenv('db_host', '127.0.0.1')
DB_PORT = getenv('db_port', 6379)
DB_PASSWORD = getenv('db_password', '')
#4 跑项目 可以在cli目录下通过ProxyPool.py启
python3 proxyPool.py schedule:爬取代理
python3 proxyPool.py webserver:启动服务
#5 测试
http://127.0.0.1:5010/get/ 发一次,取一个代理ip
四、验证码破解(打码平台)
这里需要用到第三方的打码平台,从网上的验证码图片,传给它,他就给你识别,(12306的验证码,模拟登陆12306)。
我们还可以使用一些程序去识别一些图片,但是一般识别率比较低。
4.1用python如何调用dll文件
python调用dll详解参考链接https://www.cnblogs.com/blog-rui/p/11662827.html