点赞再看,养成习惯。微信公众号搜索「Job Yan」关注这个爱发技术干货的 Coder。本文 GitHub https://github.com/JobYan/PythonPearls 已收录,还有算法学习、爬虫进阶等资料,以及个人系列文章,欢迎 Star 和完善。html
你们好,我是 「Job」。本篇文章是「保姆级」带你入门和进阶网络爬虫系列文章的开篇,在本篇文章中我会手把手教你:如何利用简单的方法骗过百度文库的反爬机制,爬取指定的文档页面,并将文档下载下来 skr~。舒适提示,本文字数较多,可能须要阅读较长时间,建议先点赞收藏,防止迷路。python
想必你们都对百度文库已经很熟悉了,百度文库如今的收费策略,简直不要太霸道。百度文库的 VIP 策略有点恶心,以前积分能够换取下载券,为了得到积分,我当时还好心的把本身的一些文档上传到了百度文库。而如今积分根本用不到了,全是 VIP。最恶心的是,我以前上传的文档明明设置的是积分下载,而百度直接设置成为 VIP 专享,因此百度在利用咱们的文档敛财,而给咱们的积分却不能下载任何文档,我能说这是平台的垄断行为吗?这样好吗?这样很差,但愿他耗子尾汁。这让我想起了之前网上流传的一张 Gif。git
可能不少人和个人感受是同样的,做为平台不能只关心本身的利益,还要考虑用户和贡献者的利益。因此,本期我们学习如何利用 Python 编写爬虫脚本,爬取某些百度文库的文档,找回一些文库用户的存在感。github
说了这么多无关的内容,接下来我们开始正式的教学内容。为了便于讲解,我把抓取的过程分红了 4 步,以下图所示:算法
须要注意的事项有两点:
第一点,咱们爬取到的文件和文库中的原文件是有区别的,以PPT类型的文件为例,咱们在文档页面看到的内容实际上是 PPT 通过渲染后的图片。也就是说浏览器中咱们看到的都是一些图片。因此咱们能够利用 Python 等编写爬虫脚本,爬取网页中的相关图片。再将这些图片合并成 PDF 文档。
第二点,不一样文件类型的爬取方式是不一样的,这里我先卖个关子。下一篇博文教你下载 Word,TXT,PPT 等类型的文档。浏览器
下面以某篇 PPT 文档为例,分步骤展开讲解。微信
首先在浏览器中访问文库首页并获取某 PPT文档 的连接。我打开文库首页以后,随便找了篇 PPT 文档。在这里以及后面的示例程序中,我就不粘贴文档的真实连接了,一概以https://wenku.baidu.com/view/xxx.html
来代替。网页截图以下:cookie
获取文档网页连接之后,咱们即可以利用 Python 自带的 requests 库获取网页内容的获取。网页的代码以下:网络
import requests url = "https://wenku.baidu.com/view/xxx.html" header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'} res = requests.get(url, headers=header) # Get 网页内容
我猜这个时候,不少小伙伴已经跃跃欲试了,很快就抄起键盘使出了一套 Ctrl+C
和 Ctrl+V
的组合拳,趁 IDE 没有防备,很快啊,反手就是一个 F5
。此时,一丝不易觉察的笑容从你的脸上掠过,然而年轻人你笑得太早了,很快啊,你就露出惊讶的神情,「Job」老师,发生什么事了?原来啊,就在前些日子,百度文库修改了反爬策略,之前能够很容易获取到的网页内容,如今没法正常获取了。函数
从下图中咱们能够看出,使用上述代码下载到的 html 内容和本来的 html 内容是不同的。左边红框中的内容利用上面的代码抓取到的 html 内容,右侧红框中的内容是 Firefox 浏览器保存的离线网页内容。二者是不一致的,而且左侧的内容中黄色框标识的地方好像表示文库团队在收集数据从而达到更好的反爬效果。[舒适提示:点击图片即可查看高清大图]
而在上面的代码正是经过以前简单的方式进行爬取,因此出现了问题。不过不要慌,接下来,我会教会你如何去解决这个问题。接下来,我们欣赏一副优美的图片,让心灵的窗户休息一下。
相信看到这里的小伙伴都是很想知道问题答案的,我也就不卖关子了,直接放大招(贴代码)。下面的代码是我通过了一下午的调试和观察得出来的解决问题的方法。
import requests url = "https://wenku.baidu.com/view/xxx.html" header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'} res = requests.get('https://wenku.baidu.com') cookie = res.cookies # Get 网页内容 res = requests.get(url, headers=header, cookies=cookie)
在说出问题解决方法以前,请你们认真阅读上面的代码,并找出和以前代码的不一样之处。
上面的代码很简单,相信细心的小伙伴已经很轻松就发现了和以前代码的不一样之处,那就是在抓取目标网页以前,先抓取了一条和百度相关的网页,在这里我们先抓取的是百度文库的首页,即 https://www.wenku.baidu.com
,而后利用此次的 cookies 信息,对文库的指定网页进行抓取。
其实简单理解就是:首先让百度文库认为我们是有身份的,这里的身份就是我们访问百度文库首页得到的 cookies,而后凭借该身份就能够抓取百度文库的指定网页。趁其还没有觉察之际,我们赶忙把指定网页爬取下来,「来骗来偷袭」。从目前来看这种简单的技巧能够颇有效的解决被百度反爬的问题。
经过上述操做以后,咱们获取到了和浏览器中相同的网页内容。左边红框中的内容利用上面的代码抓取到的 html 内容,右侧红框中的内容是 Firefox 浏览器保存的离线网页内容。二者是不一致的,不过不要紧,咱们已经抓取到了咱们想要的内容。
这部分是本文的关键。由前面的内容咱们知道了,PPT 以图片的形式存在于网页中。那么很简单,咱们首先能够利用浏览器的网页调试功能来分析网页中的各个元素。能够看到网页上的 HTML 元素的嵌套就跟洋葱似的。一层嵌套着一层,而咱们获取的图片的连接是洋葱里的最里层,因此咱们要一层一层的拨开它的心
,从而获取图片的资源连接。下图展现了剥洋葱的过程,很生动形象。经过这种方法,咱们能够很轻松的找到 PPT 页面的连接。
在找到第一页的 PPT 图片以后,其他图片很能够很容易的被找到,以下图绿框中标注的内容。经过这种方式咱们能够很方便的找到各页图片的连接,但要程序去作,那应该怎样去编写代码呢?别慌,其实咱们找到图片的连接以后,接下来编写代码的工做就简单了,'人生苦短,我用 Python',Python 中有许多现成的库函数能够帮助咱们完成这个简单的任务,接下来咱们会利用BeautifulSoup
来查找图片的连接。
为方便你们的理解,我先把代码放到下方,请你们先阅读一遍,接下来我会对关键地方进行讲解。
import html from bs4 import BeautifulSoup html_content = res.text # 网页文本内容 # 接下来,利用 Beautiful 找寻 res.text 中的相关字段 soup = BeautifulSoup(html_content, 'html.parser') title = soup.title.text title = title.replace(' - 百度文库', '') print('文章标题:' + title) # 利用 BeautifulSoup 获取文档图片的连接 img_srcs = soup.find_all('img') img_num = len(img_srcs) print(f"该 PPT 文档总共包含 {img_num} 张图片。")
在第 6 行,使用 BeautifulSoup 解析网页内容,可以获得一个 BeautifulSoup
的对象。(更多 BeautifulSoup 的内容,请查阅官方的帮助文档,放心该文档提供了中文版的)。接下来,就能够很方便的获取网页内容中标签的相关信息。以下图所示,图片的连接包含于 标签中,因此咱们利用
img_srcs = soup.find_all('img')
能够很轻松的获取该网页中包含的所有 标签。
可能有小伙伴会问, 标签中会不会包含着其余非 PPT 图片的连接?颇有可能,但我如今并未发现这种状况,因此你们能够按照这种方式来获取图片的连接。
接下来的工做就很简单了,先上代码后解释,关键内容已写注释。
# 定义下载图片的函数,方便后续下载图片 def download_img(img_url, img_name, header, cookie): try: r = requests.get(img_url, headers=header, stream=True, cookies=cookie) if r.status_code == 200 or r.status_code == 206: open(img_name, 'wb').write(r.content) # 将内容写入图片 return True, None except Exception as e: return False, traceback.format_exc() i = 0 # 遍历获取到的标签列表 for img_src in img_srcs: i = i + 1 print(f"正在下载第 {i} 张图片,进度 {i} / {img_num} 。") # <img src="https://wkretype.bdimg.com/retype/zoom/xxx" alt=""> img_herf = img_src.get('src') # 获取图像连接 if img_herf == None: # 有的图片用的是'data-src' # 即:<img data-src="https://wkretype.bdimg.com/retype/zoom/xxx" alt=""> img_herf = img_src.get('data-src') # 获取图像连接 try: img_herf = html.unescape(img_herf) except: print(f"第 {i} 张图片下载失败。") continue img_name = str(i) + '.png' # 下载图片 ret_val, message = download_img(img_herf, img_name, header, cookie) if ret_val: print(f"第 {i} 张图片下载成功 。") else: print(f"第 {i} 张图片下载失败,错误信息以下:\n", message)
下面的工做也很简单,将下载到的图片输出到 PDF 文件中。先上代码,后解释。
import fitz doc = fitz.open() img_dir, _ = os.path.split(img_paths[0]) for img_path in img_paths: imgdoc = fitz.open(img_path) # 打开图片 pdfbytes = imgdoc.convertToPDF() # 使用图片建立单页的 PDF imgpdf = fitz.open("pdf", pdfbytes) doc.insertPDF(imgpdf) # 将当前页插入文档 # 保存在图片文件夹下 save_pdf_path = os.path.join(img_dir, pdf_name) if os.path.exists(save_pdf_path): os.remove(save_pdf_path) doc.save(save_pdf_path) # 保存pdf文件 doc.close()
在上面的代码中,咱们借助 fitz 库的帮助,完成了将图片直接输出为 PDF 文件的工做。
总结:
在本篇文章中,咱们学习了如何避开百度的反爬机制,得到 PPT 的网页内容,并利用 BeautifulSoup 对网页内容进行解析,获取图片连接地址,接着,咱们经过连接地址下载图片,最后,咱们把图片合并保存为 PDF 文档的形式。
若是个人文章帮到了你,请给一个当心心,有了你的鼓励我后续会更有动力创做出更加优质的文章,从而帮助到更多的小伙伴。固然,若是你以为本文章在某些方面是不够好的,请在评论区留言,你的意见对我真的很是重要,谢谢。
我已经将本文章中讲述的源码都打包好了,而且还利用 pyinstaller 生成了可执行文件,若是你有这方面需求的话,请关注公众号「Job Yan」,后台回复百度文库,便可获取相关文件,后期程序更新的话,我会第一时间将相应文件更新到微信公众号后台。本系列教程持续更新,若是你也对爬虫感兴趣,欢迎关注,我们共同进步,一块儿成长。
欢迎各位小伙伴用大家心爱的大手机扫描屏幕上的二维码(长按二维码能够识别或者保存到本地哟😘)。这是个套了支付宝马甲的公众号二维码,不信你就扫扫看(手动斜眼)。
文章持续更新,能够微信公众号搜索「Job Yab」第一时间阅读,本文 GitHub https://github.com/JobYan/PythonPearls 已经收录,还有算法学习、爬虫进阶等资料,欢迎 Star 和完善。