Python入门到实战(七)爬虫获取豆瓣电影TOP250、多线程、Request、BeautifulSoup、HTML/CSS/JavaJcript、开发者工具、HTTPS请求、域名IP、
I 前置知识准备:
目标网站的网站结构
爬虫的学习需要对前端技术和网络请求原理有些许了解,在这里,简要提一下。
网络客户端技术:
HTML
超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言、标记语言简单理解,就是一致的语义空间下,怎么做的问题。比如
标签中放文字,<div>标签就像一个容器,<title>是网页的标题…
那么在拿到HTML代码直接按照标签读就可以,用栈结构应该就能实现。入一个标签代表什么,直到入一个尾标签,不断出栈,将中间的内容都理解为xxx就可以。
CSS
层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。
CSS通俗来说就是负责装饰,装潢作用。
JavaScript
JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。
JS通俗来说负责页面动态处理,比如用户点击,如何响应,路由、传参等、
开发者工具查看前端代码
以上三种语言都可以出现在同一个网页前端代码里,想看代码十分容易,摁F12,或者选择浏览器的开发者工具就可以查看网页源代码。
网络请求原理
HTTP(hyperText transfer protocol)
超文本传输协议是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
C/S
上面的三种语言为什么叫网络客户端技术,因为这是直接展示给用户观看的,以人性化的界面,方便用户操作,降低软件,平台的使用难度
用户无需管服务端,后台数据库等如何进行操作的。只许在屏幕点击几下就能完成业务流程
所谓CS架构,就是client 对server架构、也称作 browser /server架构
当今网络大环境仍然还是多用户对服务器,数据在传输过程中也会经过诸多结点,由于http都是明文传输,为了避免数据被篡改和窃听,在密码学的基础上衍生出了HTTPS
HTTPS
HTTPS其实就要用到SSL:Secure Sockets Layer 安全套接字协议
在应用层和传输层进行加密,此处涉及密码学和网络安全知识,不详细展开
域名/IP
IP是Internet Protocol(网际互连协议)的缩写,是TCP/IP体系中的网络层协议。设计IP的目的是提高网络的可扩展性:一是解决互联网问题,实现大规模、异构网络的互联互通;二是分割顶层网络应用和底层网络技术之间的耦合关系,以利于两者的独立发展。根据端到端的设计原则,IP只为主机提供一种无连接、不可靠的、尽力而为的数据包传输服务。
IP就是接到互联网上的主机,需要与别的主机沟通交流,需要有一个唯一标识符~,就是IP,抽象出来,网络层中是通过IP来找端的。
由于IP地址具有不方便记忆并且不能显示地址组织的名称和性质等缺点,人们设计出了域名,并通过网域名称系统(DNS,Domain Name System)来将域名和IP地址相互映射,使人更方便地访问互联网,而不用去记住能够被机器直接读取的IP地址数串。
此处不展开论述
工具:
Request可以轻松实现HTTP请求
BeautifulSoup可以轻松解析网页结构
II 编写代码
安装库
pip install beautifulsoup4
pip install lxml
pip install requests
pip install fake-useragent
如果长时间安装不下来或者安装失败请参考我几天前写的:
Python入门到实战(五)自动化办公…pip install xx 切换国内镜像服务器下载,解决下载慢的问题
分析网页
仔细观察,
URLhttps://movie.douban.com/top250?start=0&filter=
每点击一下,?start=25,观察得知是25的倍数,其他不变,故只需通过定一个变量i从0-多少页去乘25即可,这个页面是start=50:
由上可以写一个测试:
import os
print("工作目录",os.getcwd())
download_path='./douban'
if not os.path.exists(download_path):
os.makedirs(download_path)
def main():
start_url=['https://movie.douban.com/explore']
for i in range(1,10):
start_url.append(f'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start={i*20}')
print(start_url)
if __name__=='__main__':
main()
结果
['https://movie.douban.com/explore', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=20', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=40', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=60', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=80', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=100', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=120', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=140', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=160', 'https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=180']
PS C:\Users\ASUS\Desktop\MLCode\utilPython>
随便点一个start80,摁住CRTL+鼠标左键,就会用浏览器跳转到相应页面
开始代码
安装完成后,可以打开编辑器撸代码了
import os
import requests
from bs4 import BeautifulSoup
from urllib.request import urlretrieve
download_path='./dbTop250'
if not os.path.exists(download_path):
os.makedirs(download_path)
def download_pic(url):
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36'}
r=requests.get(url, headers=headers)
soup=BeautifulSoup(r.text,'lxml')
#get large div
content=soup.find('div',class_='article')
#print(content) #打印出class 为article标签下的内容
#get all film pic
images=content.find_all('img')#包含img的都选入images
#get all film's name and downlad address
pic_link_list=[image['src'] for image in images]
pic_name_list=[image['alt'] for image in images]
for picname, piclink in zip(pic_name_list,pic_link_list):
urlretrieve(piclink, f'{download_path}/{picname}.jpg' )
# html=requests.get(piclink) //法二、都测试成功
# with open(f'{download_path}/{picname}.jpg','wb') as f: #二进制字节流写入
# f.write(html.content)
print(f'{url}所有电影图片下载完成')
def main():
start_url=['https://movie.douban.com/top250']
for i in range(0,11):
start_url.append(f'https://movie.douban.com/top250?start={i*25}&filter=')
for url in start_url:
download_pic(url)
if __name__=='__main__':
main()
运行结果
运行试试,结果为:
https://movie.douban.com/top250所有电影图片下载完成
https://movie.douban.com/top250?start=0&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=25&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=50&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=75&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=100&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=125&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=150&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=175&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=200&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=225&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=250&filter=所有电影图片下载完成
多线程
现在的run time
想要知道效率是否提升,就需要知道前后运行时间,从而进行对比!
想知道时间开销,就需要import time
在大for循环(关键代码,主要耗时代码)前加上:startTime=time.time()
for循环结束后加上endTime=time.time()
并打印出结果:print(f’run time={endTime-startTime}’)
运行结果:
https://movie.douban.com/top250所有电影图片下载完成
https://movie.douban.com/top250?start=0&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=25&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=50&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=75&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=100&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=125&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=150&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=175&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=200&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=225&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=250&filter=所有电影图片下载完成
run time=51.424378395080566
III 多线程优化
使用多线程池优化后,main方法代码如下:
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
def main():
start_url=['https://movie.douban.com/top250']
for i in range(0,11):
start_url.append(f'https://movie.douban.com/top250?start={i*25}&filter=')
startTime=time.time()
# for url in start_url:
# download_pic(url)
#使用线程池
with ThreadPoolExecutor(max_workers=10) as executor:
futures=[]
for url in start_url:
future=executor.submit(download_pic,url)
futures.append(future)
wait(futures, return_when=ALL_COMPLETED)
endTime=time.time()
print(f'run time={endTime-startTime}')
https://movie.douban.com/top250?start=175&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=50&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=0&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=100&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=25&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=250&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=200&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=150&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=75&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=125&filter=所有电影图片下载完成
https://movie.douban.com/top250?start=225&filter=所有电影图片下载完成
run time=20.880120754241943
时间快了一半还多
相较于单线程,可以简单理解
本来你打字若是计算机处理器就等待着你输入字符,把用户敲击键盘输入的速度和计算机的速度相比较,那将是很浪费的。
那计算机就可以处理qq的消息,音乐的播放等进程。而进程之内又可以有线程,使得多核CPU并发处理多线程,相较于在单核上跑进程,快速了许多。
线程也是小的进程、是OS中最小调度单位,当初学的操作系统也快忘光了。搬过来多线程无疑在此可以增大吞吐量,提高内存和处理器利用率,充分使计算机发挥了性能、
后续会继续深入的学习并理解Python中的多线程~到时再写blog