相关python库
①获取网页需要
发起web请求,python提供了
requests②阅读网页需要
进行html解析,python提供了
beautifulsoup4
pip install requests beautifulsoup4
1.发起web请求
发起请求,得到响应。我们首先要清楚,请求要告诉服务器哪些信息?在响应中能获得哪些信息?在http协议的 请求/响应 格式中,
它们各自包含了3部分内容(且一一对应):①请求行 / 状态行:主要是 请求地址和响应状态②请求头 / 响应头:描述本次 请求/响应 的元信息③请求参数 / 响应正文:请求数据和网页内容除此之外,还可能用到cookie。如果目标网站需要登录,就得用浏览器工具,取出
cookie里的sessionId,然后在编码时加入请求。下面了解一下requests如何发起请求,获得响应:
import requests# 发起请求:get/post/put/delete/head/options请求参数 = {'key': 'value'}请求头 = { 'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'}r = requests.get('https://woods240.cn', data=请求参数, cookies={'key': 'value'}, headers=请求头)# 设置响应的解码方式r.encoding = 'utf-8'print('状态码:', end='')print(r.status_code)print('响应头:', end='')print(r.headers)print('响应正文是文本:', end='')print(r.text)print('响应正文是文本二进制:', end='')print(r.content)
它抓取了我的博客首页,VSCode运行结果:
2.解析html
获得网页后,就可以从中抓取有用的内容了。这时轮到beautifulsoup4闪亮登场,通常用它干2件事:①根据目标网页的特点,抓取特定tag,语法为 “
soup.find_all('tag')”②我们要的内容,就在tag的某个属性中
,语法为 “ tag.get('attr')
”用一个简单的例子,熟悉它的语法:
import requestsfrom bs4 import BeautifulSoup# 获取网页r = requests.get('https://woods240.cn')r.encoding = 'utf-8'if r.status_code == 200: # 阅读网页 soup = BeautifulSoup(r.text, 'html.parser') # 1)抓取tag for link in soup.find_all('a'): # 2)获得tag的属性 print(link.get('href'))
这个例子
抓出了网页中所有的链接(如果顺着链接继续抓,就成了“爬虫”),
VSCode运行结果:
3.示例:爬网站图片
有了以上基础,我们就可以写个
简单的网络爬虫了。需求:在百度新闻 “http://news.baidu.com/” 上抓取图片思路:①根据url获得网页内容,并添加 网页爬取记录
②从网页中抓取图片:
a.处理路径
b. 如果图片没存过,就保存、并添加图片存储记录③
从网页中 抓取
链接:
a.处理路径 b.
如果网页没爬过、且是站内链接,就继续爬:重复①②③(递归)
import requestsfrom bs4 import BeautifulSoupfrom urllib.parse import urljoinimport osimport json# 目标网站和下载目录SITE = 'http://news.baidu.com/'DOWNLOAD_DIR = r'D:\grabDownload'if not os.path.exists(DOWNLOAD_DIR): os.mkdir(DOWNLOAD_DIR)grabedUrlList = [] # 网页爬取记录grabedImgList = [] # 图片存储记录imgSequence = 0 # 保存图片时的序号# 爬虫函数def grab(url): # ①根据url获得网页内容,并添加网页爬取记录 grabedUrlList.append(url) r = requests.get(url) r.encoding = 'utf-8' if r.status_code == 200: soup = BeautifulSoup(r.text, 'html.parser') # ②从网页中抓取图片: for img in soup.find_all('img'): # a.处理路径 src = processUrl(url, img.get('src')) if src == None: continue # b.如果图片没存过,就保存、并添加图片存储记录 if src not in grabedImgList: grabedImgList.append(src) global imgSequence imgSequence += 1 downloadImage(src, str(imgSequence) + '.png') # ③从网页中抓取链接: for a in soup.find_all('a'): # a.处理路径 href = processUrl(url, a.get('href')) if href == None: continue # b.如果网页没爬过、且是站内链接,就抓取:重复①②③(递归) if href not in grabedUrlList and str(href).startswith(SITE): grab(href) # 保存图片存储记录 imgRecordPath = os.path.join(DOWNLOAD_DIR, 'grabedImgList.json') with open(imgRecordPath, 'w') as f: json.dump(grabedImgList, f) # 保存网页爬取记录 urlRecordPath = os.path.join(DOWNLOAD_DIR, 'grabedUrlList.json') with open(urlRecordPath, 'w') as f: json.dump(grabedUrlList, f)# 处理路径def processUrl(pageUrl, linkUrl): # 剔除锚 anchorIndex = str(linkUrl).find('#') if anchorIndex > -1: linkUrl = linkUrl[:anchorIndex] # 忽略javascript: if str(linkUrl).startswith('javascript:'): linkUrl = None # 相对路径 => 绝对路径 if not str(linkUrl).startswith('http'): if str(linkUrl).startswith('/'): # 相对于网站根目录 linkUrl = urljoin(SITE, linkUrl) else: # 相对于当前页面 linkUrl = urljoin(pageUrl, linkUrl) return linkUrl# 下载图片def downloadImage(imgSrc, name): r = requests.get(imgSrc) if r.status_code == 200: imgPath = os.path.join(DOWNLOAD_DIR, name) with open(imgPath, 'wb') as f: f.write(r.content)# 开始抓取grab(SITE)
实现效果:
在细节处理上,我们要关注url处理和图片下载,下面做简要说明: ①url中包含的锚,只起到页面内定位的作用,为避免url重复抓取,应该剔除
②url中可以编写javascript,这种情况下不能作为网络地址
③url的格式可能是相对路径,可以相对于网站,也可以相对于当前页面,应处理成绝对路径,才能让python正确发送请求
④图片下载内容是二进制,保存为文件时应使用 'wb' 模式
⑤我们用
json格
式保存
了图片存储记录和网页爬取记录,方便后续查看
总结:
①网络爬虫的本质是:从多个相关网页中筛选出关注的信息,做重新整合②爬虫程序的套路是相同的,都是3个步骤:获取网页内容、抓取有用信息、抓取链接并递归爬取,不同的程序只需修改第2步