0.前言
本篇文章基于《Python编程从认知到实践》。在选取书籍中精华部分以外,还包含作者自身遇到的问题和解决方法。
1.简单的webbrowser模块示例程序
- 从命令行参数或剪贴板中取得街道地址
- 打开Web浏览器,指向该地址的页面
import webbrowser,sys,pyperclip
if __name__ == '__main__':
if len(sys.argv)>1:
address=' '.join(sys.argv[1:])
else:
address=pyperclip.paste()
webbrowser.open(address)
2.使用requests模块从Web下载文件
2.1下载一个网页示例
(base) PS C:\Users\20980> Conda activate pythonProject
(pythonProject) PS C:\Users\20980> python
Python 3.9.15 (main, Nov 24 2022, 14:39:17) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> res=requests.get('https://www.gutenberg.org/cache/epub/1112/pg1112.txt')
>>> type(res)
<class 'requests.models.Response'>
>>> res.status_code==requests.codes.ok
True
>>> len(res.text)
179380
2.2检查错误
- 可以检查Response对象的status_code属性是否等于requests.codes.ok
- 在Response对象调用raise_for_status()方法,下载失败则抛出异常(如果下载失败对于程序不算严重,可以使用try和except包裹这行代码)
3.将下载的文件保存到硬盘
在pycharm中运行这段代码:
import requests
if __name__ == '__main__':
res = requests.get('https://www.gutenberg.org/cache/epub/1112/pg1112.txt')
res.raise_for_status()
playFile=open('D://story.txt','wb')
for chunk in res.iter_content(100000):
playFile.write(chunk)
playFile.close()
结果:
过程解释:
- 调用
requests.get()
下载文件 - 用
'wb'
调用open()
,以写二进制的方式打开一个新文件(目的是保存文本中的万国码) - 利用
Request
对象的iter_content()
方法做循环 - 在每次迭代中调用
write()
,将内容写入该文件 - 调用
close()
关闭该文件
4.HTML
5.用BeautifulSoup模块解析HTML
5.1从HTML创建一个BeautifulSoup对象
bs4.BeautifulSoup()
函数调用时需要一个字符串,其中包含将要解析的HTML。bs4.BeautifulSoup()
函数返回一个BeautifulSoup
对象。
import requests,bs4
if __name__ == '__main__':
res=requests.get('https://www.bilibili.com/')
res.raise_for_status()
noStarchSoup=bs4.BeautifulSoup(res.text, "html.parser")
print(type(noStarchSoup))
- 也可以向
bs4.BeautifulSoup()
传递一个File对象。
5.2用select()
方法寻找元素
针对要寻找的元素,调用method()
方法,传入一个字符串作为CSS选择器,这样就可以取得Web页面元素。(选择器就像正则表达式)
①:
import requests
if __name__ == '__main__':
res=requests.get('https://www.apple.com.cn/')
res.raise_for_status()
text=open('D://text.txt','wb')
for chunk in res.iter_content(100000):
text.write(chunk)
text.close()
import bs4
if __name__ == '__main__':
exampleFile=open('D://text.html',encoding='utf-8')
exampleSoup=bs4.BeautifulSoup(exampleFile.read(),'html.parser')
elems=exampleSoup.select('div>span')
for i in range (5):
print(elems[i].getText())
输出:
+
搜索 apple.com.cn
取消
+
②:
5.3通过元素的属性获取数据
输入:
import bs4
if __name__ == '__main__':
soup=bs4.BeautifulSoup(open('D://example.html'),'html.parser')
spanElem=soup.select('span')[0]
print(str(spanElem))
print(spanElem.get('id'))
print(spanElem.attrs)
输出:
<span id="author">Al Sweigart</span>
author
{'id': 'author'}
5.4实践
5.4.1关于headers()
5.4.1.1为什么要加上headers()
我们一般写的爬虫会默认向服务器发送爬取请求,而一般情况下网站是不允许被爬虫访问的,输出的text信息中会出现抱歉,无法访问等字眼。我们通过更改User-Agent字段则可以实现网站请求,实现网页应答。
5.4.1.2如何寻找headers()
- 在要爬虫的网页中打开开发者工具
- 点击网络,再点击文档
- 找到标头,查看Request Headers的User-Agent字段,直接复制
- 将刚才复制的User-Agent字段构造成字典形式
5.4.2开始实践
我们选取摄图网作为例子
5.4.2.1导入库
主要的库就是requests
以及bs4
的BeautifulSoup
5.4.2.2寻找页面规律
由于这个网站查找图片时有翻页的操作,所以我们应该先弄清楚翻页时url变化的规律,不难看出,这个规律就是url='https://699pic.com/soso/xihongshi-complex---------0--'+str(i)+'.html'
5.4.2.3网站结构分析:
进入这个网站,搜索我们想查找的图片,然后进入开发者界面观察,找到headers保存下来,作为爬虫的伪装。
然后观察,正确的图片链接在何处:
不难观察出,class
值为lazy
的img
标签中,正确的图片链接就是data-original
的值。
接下来,我们就可以准备写脚本下载目标图片了。
5.4.2.4完成程序
先放出整个程序:
#我们尝试下载西红柿图片的第一页和第二页
import requests
from bs4 import BeautifulSoup
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.52'}
def Save_Pics(page_begin,page_end):
Total_Pics=0
for i in range(page_begin,page_end):
#根据要爬取的网站的翻页规律完成url的循环
url='https://699pic.com/soso/xihongshi-complex---------0--'+str(i)+'.html'
r=requests.get(url,headers=header)
r.encoding='utf-8'
if r.status_code==200:
print('该页面请求成功,开始下载')
page_content=r.text
soup = BeautifulSoup(page_content, 'html.parser')
tags = soup.find_all("img", class_='lazy')
print('该页面有 ' + str(len(tags)) + '张图像')
for tag in tags:
print(tag)
if tag['alt'] == '上海举报中心':
print('结束该页面的下载')
else:
Total_Pics+=1
image = 'https:' + tag['data-original']
print(image)
fileName = 'D:\图片\西红柿/' + str(Total_Pics) + '.jpg'
r = requests.get(image, headers=header)
f = open(fileName, 'wb')
f.write(r.content)
f.close()
else :
print('请求失败,无法下载该页')
if __name__ == '__main__':
Save_Pics(1,3)
打开文件夹,发现图片也按照标号保存完毕了:
在每一页的最后一个img
标签中,是没有data-original
的那个链接,这时已经进入到页面的末尾,因此需要加上一条判断。
6.用selenium模块控制浏览器
6.0准备工作:
6.0.1首先在环境中下载selenium
pip install selenium -i Simple Index
6.0.2安装火狐浏览器
默认安装在c盘比较好,后续操作就比较简单
6.0.3下载浏览器驱动
- Firefox 浏览器驱动:Firefox
- Chrome 浏览器驱动:Chrome
- IE 浏览器驱动:IE
- Edge 浏览器驱动:Edge
- PhantomJS 浏览器驱动:PhantomJS
- Opera 浏览器驱动:Opera
6.0.4设置环境变量
将驱动解压,分别放在对应环境中python.exe的路径中、火狐浏览器安装路径中。
然后将火狐浏览器的安装路径添加到系统环境变量中。
6.0.5测试
环境中运行下列代码:
from selenium import webdriver
if __name__ == '__main__':
browser=webdriver.Firefox()
成功打开火狐浏览器即为成功。
6.1在页面中寻找元素
WebDriver
对象有好几种方法用于在页面中寻找元素。
分为:findelement
(返回第一个元素)和findelements
(返回所有元素组成的)方法。
如果页面上没有元素匹配该方法要查找的元素,selenium模块就会抛出NoSuchElement
异常。
简单的一个例子:
from selenium import webdriver
if __name__ == '__main__':
browser=webdriver.Firefox()
browser.get('https://699pic.com/')
try:
elem=browser.find_element_by_class_name('banxin bulletin')
print('Found< %s>element with that class name!' %(elem.tag_name))
except:
print('Was not able to find an element with that name.')
但这个程序正常来说是可以找到这个元素的,但事实上并没有找到这个元素。
然后,我调查了一下,果然,这个库更新了,格式有所改动。。。
下面是新的格式:
from selenium import webdriver
from selenium.webdriver.common.by import By
if __name__ == '__main__':
browser=webdriver.Firefox()
browser.get('https://699pic.com/')
try:
elem=browser.find_element(By.CLASS_NAME,'index-header')
print('Found< %s>element with that class name!' %(elem.tag_name))
except:
print('Was not able to find an element with that name.')
输出:
Found< div>element with that class name!
6.2点击页面
findelement
和findelements
返回的WebElement
对象有一个click()
方法:
from selenium import webdriver
from selenium.webdriver.common.by import By
if __name__ == '__main__':
browser=webdriver.Firefox()
browser.get('https://www.bilibili.com/')
linkElem=browser.find_element(By.CLASS_NAME,'nav-search-btn')
print(type(linkElem))
linkElem.click()
上面这段程序完成进入bilibili网站,并且点击搜索按钮,完成事件。
6.3填写并提交表单
from selenium import webdriver
from selenium.webdriver.common.by import By
if __name__ == '__main__':
browser=webdriver.Firefox()
browser.get('https://www.bilibili.com/')
linkElem=browser.find_element(By.CLASS_NAME,'nav-search-btn')
SearchElem=browser.find_element(By.CLASS_NAME,'nav-search-input')
SearchElem.send_keys('战鹰')
linkElem.click()
6.4发送特殊键
针对不能用字符串值输入的键盘击键,这个模块解决了问题:selenium.webdriver.common.keys
由于这个模块名过长,因此我们一般在引入时,这么填写:from selenium.webdriver.common.keys import Keys
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
if __name__ == '__main__':
browser=webdriver.Firefox()
browser.get('https://www.bilibili.com/')
SearchElem=browser.find_element(By.CLASS_NAME,'nav-search-input')
SearchElem.send_keys('战鹰')
SearchElem.send_keys(Keys.ENTER)
6.5点击浏览器按钮
四个方法:
browser.back()
browser.forward()
browser.refresh()
browser.quit()