Beautifulsoup和selenium的简单使用
Beautifulsoup和selenium的简单使用
requests库的复习
好久没用requests
了,因为一会儿要写个简单的爬虫,所以还是随便写一点复习下。
import requests
r = requests.get('https://api.github.com/user', auth=('haiyu19931121@163.com', 'Shy18137803170'))
print(r.status_code) # 状态码200
print(r.json()) # 返回json格式
print(r.text) # 返回文本
print(r.headers) # 头信息
print(r.encoding) # 编码方式,一般utf-8
# 当写入文件比较大时,避免内存耗尽,可以一次写指定的字节数或者一行。
# 一次读一行,chunk_size=512为默认值
for chunk in r.iter_lines():
print(chunk)
# 一次读取一块,大小为512
for chunk in r.iter_content(chunk_size=512):
print(chunk)
注意iter_lines
和iter_content
返回的都是字节数据,若要写入文件,不管是文本还是图片,都需要以wb
的方式打开。
Beautifulsoup的使用
进入正题,早就听说这个著名的库,以前写爬虫用正则表达式虽然不麻烦,但有时候会匹配不准确。使用Beautifulsoup可以准确从HTML标签中提取数据。虽然是慢了点,但是简单好使呀。
from bs4 import BeautifulSoup
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>
"""
# 就注意一点,第二个参数指定解析器,必须填上,不然会有警告。推荐使用lxml
soup = BeautifulSoup(html_doc, 'lxml')
print(soup.prettify())
<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 class="sister" href="http://example.com/elsie" id="link1">
Elsie
</a>
,
<a class="sister" href="http://example.com/lacie" id="link2">
Lacie
</a>
and
<a class="sister" href="http://example.com/tillie" id="link3">
Tillie
</a>
;
and they lived at the bottom of a well.
</p>
<p class="story">
...
</p>
</body>
</html>
soup.prettify()
可以格式化html代码,可以看到输出已经被格式化,更具有可读性。
紧接着上面的代码,看下面一些简单的操作。使用点属性的行为,会得到第一个查找到的符合条件的数据。是find
方法的简写。
soup.a
soup.find('p')
上面的两句是等价的。
# soup.body是一个Tag对象。是body标签中所有html代码
print(soup.body)
<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 class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>
# 获取body里所有文本,不含标签
print(soup.body.text)
# 等同于下面的写法
soup.body.get_text()
# 还可以这样写,strings是所有文本的生成器
for string in soup.body.strings:
print(string, end='')
The Dormouse's story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
...
# 获得该标签里的文本。
print(soup.title.string)
The Dormouse's story
# Tag对象的get方法可以根据属性的名称获得属性的值,此句表示得到第一个p标签里class属性的值
print(soup.p.get('class'))
# 和下面的写法等同
print(soup.p['class'])
['title']
# 查看a标签的所有属性,以字典形式给出
print(soup.a.attrs)
{'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}
# 标签的名称
soup.title.name
title
find_all
使用最多的当属find_all / find
方法了吧,前者查找所有符合条件的数据,返回一个列表。后者则是这个列表中的第一个数据。find_all
有一个limit
参数,限制列表的长度(即查找符合条件的数据的个数)。当limit=1
其实就成了find
方法 。
find_all
同样有简写方法。
soup.find_all('a', id='link1')
soup('a', id='link1')
上面两种写法是等价的,第二种写法便是简写。
find_all(self, name=None, attrs={}, recursive=True, text=None,
limit=None, **kwargs)
name
name
就是想要搜索的标签,比如下面就是找到所有的p
标签。不仅能填入字符串,还能传入正则表达式、列表、函数、True。
# 传入字符串
soup.find_all('p')
# 传入正则表达式
import re
# 必须以b开头
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
# 含有t就行
for tag in soup.find_all(re.compile("t")):
print(tag.name)
# html
# title
# 传入列表表示,一次查找多个标签
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>]
传入True
的话,就没有限制,什么都查找了。
recursive
调用tag的 find_all()
方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
。
# title不是html的直接子节点,但是会检索其下所有子孙节点
soup.html.find_all("title")
# [<title>The Dormouse's story</title>]
# 参数设置为False,只会找直接子节点
soup.html.find_all("title", recursive=False)
# []
# title就是head的直接子节点,所以这个参数此时无影响
a = soup.head.find_all("title", recursive=False)
# [<title name="good">The Dormouse's story</title>]
keyword和attrs
使用keyword,加上一个或者多个限定条件,缩小查找范围。
# 查看所有id为link1的p标签
soup.find_all('a', id='link1')
如果按类查找,由于class关键字Python已经使用。可以用class_
,或者不指定关键字,又或者使用attrs
填入字典。
soup.find_all('p', class_='story')
soup.find_all('p', 'story')
soup.find_all('p', attrs={"class": "story"})
上面三种方法等价。class_
可以接受字符串、正则表达式、函数、True。
text
搜索文本值,好像使用string参数也是一样的结果。
a = soup.find_all(text='Elsie')
# 或者,4.4以上版本请使用text
a = soup.find_all(string='Elsie')
text参数也可以接受字符串、正则表达式、True、列表。
CSS选择器
还能使用CSS选择器呢。使用select方法就好了,select始终返回一个列表。
列举几个常用的操作。
# 所有div标签
soup.select('div')
# 所有id为username的元素
soup.select('.username')
# 所有class为story的元素
soup.select('#story')
# 所有div元素之内的span元素,中间可以有其他元素
soup.select('div span')
# 所有div元素之内的span元素,中间没有其他元素
soup.select('div > span')
# 所有具有一个id属性的input标签,id的值无所谓
soup.select('input[id]')
# 所有具有一个id属性且值为user的input标签
soup.select('input[id="user"]')
# 搜索多个,class为link1或者link2的元素都符合
soup.select("#link1, #link2")
一个爬虫小例子
上面介绍了requests和beautifulsoup4的基本用法,使用这些已经可以写一些简单的爬虫了。来试试吧。
此例子来自《Python编程快速上手——让繁琐的工作自动化》[美] AI Sweigart
这个爬虫会批量下载XKCD漫画网的图片,可以指定下载的页面数。
import os
import requests
from bs4 import BeautifulSoup
# exist_ok=True,若文件夹已经存在也不会报错
os.makedirs('xkcd')
url = 'https://xkcd.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/57.0.2987.98 Safari/537.36'}
def save_img(img_url, limit=1):
r = requests.get(img_url, headers=headers)
soup = BeautifulSoup(r.text, 'lxml')
try:
img = 'https:' + soup.find('div', id='comic').img.get('src')
except AttributeError:
print('Image Not Found')
else:
print('Downloading', img)
response = requests.get(img, headers=headers)
with open(os.path.join('xkcd', os.path.basename(img)), 'wb') as f:
for chunk in response.iter_content(chunk_size=1024*1024):
f.write(chunk)
# 每次下载一张图片,就减1
limit -= 1
# 找到上一张图片的网址
if limit > 0:
try:
prev = 'https://xkcd.com' + soup.find('a', rel='prev').get('href')
except AttributeError:
print('Link Not Exist')
else:
save_img(prev, limit)
if __name__ == '__main__':
save_img(url, limit=20)
print('Done!')
Downloading https://imgs.xkcd.com/comics/quantum.png
Downloading https://imgs.xkcd.com/comics/communicating.png
Downloading https://imgs.xkcd.com/comics/sports_knowledge.png
Downloading https://imgs.xkcd.com/comics/4th_of_july.png
Downloading https://imgs.xkcd.com/comics/emoji_movie.png
Downloading https://imgs.xkcd.com/comics/existence_proof.png
Downloading https://imgs.xkcd.com/comics/telephoto.png
Downloading https://imgs.xkcd.com/comics/refresh_types.png
Downloading https://imgs.xkcd.com/comics/once_per_day.png
...
Done!
多线程下载
单线程的速度有点慢,比如可以使用多线程,由于我们在获取prev
的时候,知道了每个网页的网址是很有规律的。它像这样https://xkcd.com/1630
。只是最后的数字不一样,所以我们可以很方便地使用range
来遍历。
import os
import threading
import requests
from bs4 import BeautifulSoup
os.makedirs('xkcd')
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/57.0.2987.98 Safari/537.36'}
def download_imgs(start, end):
for url_num in range(start, end):
img_url = 'https://xkcd.com/' + str(url_num)
r = requests.get(img_url, headers=headers)
soup = BeautifulSoup(r.text, 'lxml')
try:
img = 'https:' + soup.find('div', id='comic').img.get('src')
except AttributeError:
print('Image Not Found')
else:
print('Downloading', img)
response = requests.get(img, headers=headers)
with open(os.path.join('xkcd', os.path.basename(img)), 'wb') as f:
for chunk in response.iter_content(chunk_size=1024 * 1024):
f.write(chunk)
if __name__ == '__main__':
# 下载从1到30,每个线程下载10个
threads = []
for i in range(1, 30, 10):
thread_obj = threading.Thread(target=download_imgs, args=(i, i + 10))
threads.append(thread_obj)
thread_obj.start()
# 阻塞,等待线程执行结束都会等待
for thread in threads:
thread.join()
# 所有线程下载完毕,才打印
print('Done!')
来看下结果吧。
初步了解selenium
selenium用来作自动化测试。使用前需要下载驱动,我只下载了Firefox和Chrome的。网上随便一搜就能下载到了。接下来将下载下来的文件其复制到将安装目录下,比如Firefox,将对应的驱动程序放到C:\Program Files (x86)\Mozilla Firefox
,并将这个路径添加到环境变量中,同理Chrome的驱动程序放到C:\Program Files (x86)\Google\Chrome\Application
并将该路径添加到环境变量。最后重启IDE开始使用吧。
模拟百度搜索
下面这个例子会打开Chrome浏览器,访问百度首页,模拟输入The Zen of Python
,随后点击百度一下
,当然也可以用回车代替。Keys
下是一些不能用字符串表示的键,比如方向键、Tab、Enter、Esc、F1~F12、Backspace等。然后等待3秒,页面跳转到知乎首页,接着返回到百度,最后退出(关闭)浏览器。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
browser = webdriver.Chrome()
# Chrome打开百度首页
browser.get('https://www.baidu.com/')
# 找到输入区域
input_area = browser.find_element_by_id('kw')
# 区域内填写内容
input_area.send_keys('The Zen of Python')
# 找到"百度一下"
search = browser.find_element_by_id('su')
# 点击
search.click()
# 或者按下回车
# input_area.send_keys('The Zen of Python', Keys.ENTER)
time.sleep(3)
browser.get('https://www.zhihu.com/')
time.sleep(2)
# 返回到百度搜索
browser.back()
time.sleep(2)
# 退出浏览器
browser.quit()
send_keys
模拟输入内容。可以使用element的clear()
方法清空输入。一些其他模拟点击浏览器按钮的方法如下
browser.back() # 返回按钮
browser.forward() # 前进按钮
browser.refresh() # 刷新按钮
browser.close() # 关闭当前窗口
browser.quit() # 退出浏览器
查找方法
以下列举常用的查找Element的方法。
方法名 | 返回的WebElement |
---|---|
find_element_by_id(id) | 匹配id属性值的元素 |
find_element_by_name(name) | 匹配name属性值的元素 |
find_element_by_class_name(name) | 匹配CSS的class值的元素 |
find_element_by_tag_name(tag) | 匹配标签名的元素,如div |
find_element_by_css_selector(selector) | 匹配CSS选择器 |
find_element_by_xpath(xpath) | 匹配xpath |
find_element_by_link_text(text) | 完全匹配提供的text的a标签 |
find_element_by_partial_link_text(text) | 提供的text可以是a标签中文本中的一部分 |
登录CSDN
以下代码可以模拟输入账号密码,点击登录。整个过程还是很快的。
browser = webdriver.Chrome()
browser.get('https://passport.csdn.net/account/login')
browser.find_element_by_id('username').send_keys('haiyu19931121@163.com')
browser.find_element_by_id('password').send_keys('**********')
browser.find_element_by_class_name('logging').click()
以上差不多都是API的罗列,其中有自己的理解,也有照搬官方文档的。
by @sunhaiyu
2017.7.13
Beautifulsoup和selenium的简单使用的更多相关文章
- [python] 网络数据采集 操作清单 BeautifulSoup、Selenium、Tesseract、CSV等
Python网络数据采集操作清单 BeautifulSoup.Selenium.Tesseract.CSV等 Python网络数据采集操作清单 BeautifulSoup.Selenium.Tesse ...
- Python+selenium之简单介绍unittest单元测试框架
Python+selenium之简单介绍unittest单元测试框架 一.unittest简单介绍 unittest支持测试自动化,共享测试用例中的初始化和关闭退出代码,在unittest中最小单元是 ...
- python+selenium之简单介绍继承
python+selenium之简单介绍继承 一.此例简单的介绍一下继承 1.面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制.继承完全可以理解成类之间的类型和子类型 ...
- Beautifulsoup 和selenium 的查询
Selenium There are vaious strategies to locate elements in a page. You can use the most appropriate ...
- 自动化测试之selenium工具简单介绍
一.selenium简单介绍 1.selenium的成员 2.selenium工作原理 二.webdrive 常见元素定位
- 【Python Selenium】简单数据生成脚本
最近因工作需要,写了一个简单的自动化脚本,纯属学习,顺便学习下selenium模块. 废话不多说,直接上代码!! 这里一位大神重写了元素定位.send_keys等方法,咱们直接进行调用. 适用Pyth ...
- BeautifulSoup与aiohttp的简单应用-爬取《网上中华五千年》音频
香港电台的节目素质都比较不错,其中有个<中华五千年>的节目是以情景剧与旁白的形式来展示历史故事,由传说时代一直到民国,1983年首播至2000年,非常长寿的一个节目.网上能找到版本声音非常 ...
- Selenium:简单的尝试一下
一.创建maven工程引入依赖 1)创建项目 创建一个简单的maven工程即可 这里我使用jar项目进行简单的演示 2)引入依赖 <dependencies> <dependency ...
- python+selenium进行简单验证码获取
# _*_ coding:utf-8 _*_from PIL import Imagefrom selenium import webdriverimport pytesseractimport ti ...
随机推荐
- twisted学习之reactor
reactor是twisted框架里面一个很重要的抽象,它为我们实现了循环,所以我们不用再去实现循环了. reactor有如下特点: 1.reactor循环会一致运行下去,可以使用Ctrl+C或者相关 ...
- AutoResetEvent类的使用
线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号.如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程通过调用 Set 发出资源可用的 ...
- React Native 仿天猫物流跟踪时间轴
最近心血来潮开始学习ReactNative,正好最近有一个项目可能会用到时间轴,页面原型类似于天猫的物流跟踪,如下图 分析之后决定使用ListView来实现,左边的时间轴则使用Art来绘制. 分析左边 ...
- PostgreSQL数据库web维护客户端工具软件
TreeSoft数据库管理系统使用JAVA开发,采用稳定通用的springMVC +JDBC架构,实现基于WEB方式对 MySQL,Oracle,PostgreSQL 等数据库进行维护管理操作. 功能 ...
- 【PHP】最详细PHP从入门到精通(四)——PHP中的字符串
PHP从入门到精通 之PHP中的字符串 大家好,继续跟进PHP最详尽的知识更新,本周,跟大家重点讲一下PHP中字符串的使用.在PHP中,字符串是非常重要的一个概念,基本上大家想到的字符串的处理功能, ...
- 《HelloGitHub》第 15 期
公告 这段时间没怎么写文章,跑去写 https://hellogithub.com 这个网站了,现在已经顺利上线,功能后面会持续迭代. 最后,这个 https://hellogithub.com 网站 ...
- is not allowed to connect to this MySQL server
解决办法: 这是告诉你没有权限连接指定IP的主机mysql --user=root -p; use mysql; GRANT SELECT,INSERT,UPDATE,DELETE ON host.* ...
- http请求的完整过程
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1. 建立TCP连接 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该 ...
- 三、SolrCloud的搭建
本次安装是单台虚拟机安装,所以采用伪集群的方式进行安装,如果是真正的生产环境,将伪集群的ip改下就可以了,步骤是一样的. SolrCloud结构图如下: 环境准备: CentOS-6.4-i386-b ...
- PageSlider中CSS3动画在除首屏之外先加载页面后执行动画的问题
PageSlider中CSS3动画在除首屏之外先加载页面后执行动画的问题,PageSlider中加入CSS3动画的话,默认只有首屏是从无到有执行动画,其他屏都是显示下页面再执行动画 这就造成其他屏的动 ...