Python爬虫入门实践

写这篇博客,一来是整理我最近一两个月的数据抓取经验,二来是帮助新手快速入门爬虫。听到爬虫这个词很多人可能会联想到谷歌,百度,必应等搜索引擎,它们拥有强大的数据检索能力,为我们查找资料提供了极大的帮助。这些搜索引擎之所以强大就是因为它们有一个强大的数据抓取系统。下面我们从0到1逐层展开讲解。

基础

其实爬虫很简单,归结起来就是下面两个步骤:

  1. 获取网页源代码
  2. 解析源代码获取需要的信息

获取网页源代码

在Python3中,获取网页源代码通常有两种方式:第一种是通过Python3自带的urllib库中的request.urlopen函数来请求网页源代码;第二种方式也是最常使用的方式就是使用requests库来实现网页的抓取。

urllib

首先我先来简单的介绍一下urllib库请求网页的方法:

from urllib.request import urlopen
response = urlopen('https://pixabay.com/en/') #抓取全球著名免费矢量图网站pixabay
html = response.read()

requests

下面开始介绍本教程获取网页源代码主要使用的工具:requests
requests的使用很简单和urllib类似:

import requests
response = requests.get('https://pixabay.com/en/') #注意一定要加上url前面的安全协议https或者http不然系统会报错。
response.encoding = 'utf-8' #设置网页的源代码编码格式为utf-8,你可以根据具体情况设置诸如gbk(国标)等编码格式。
html = response.text #获取源代码

解析HTML

关于HTML我简要的说明一下:对于整个网页来说,它是使用html标记语言编写的,所以网页中的每一个元素都是一个节点,其中html标签用于包裹整个网页,head标签用于一些不需要可视化的代码编写其中包括网页的标题,引用的css文件和js文件等。而网站的主体被body标签包裹。body标签中有图层标签div(主要的标签)、img标签(图片标签)等。而每个标签都有一些属性比如class(类)、id(编号)等。其中id在整个网页中是唯一指定的,而class属性并不唯一。我们可以通过标签的层次关系以及这些标签的属性来定位我们需要抓取的数据。学习网络爬虫需要掌握一定的网页知识,如果读者欠缺这方面的知识可以前往菜鸟教程学习有关html以及css有关的知识。

解析HTML或者XML的工具或框架有很多,最常用的有:

  1. BeautifulSoup:使用正则表达式编写的html解析库
  2. lxml:通过xml的节点查找信息的网页解析库(速度很快)
  3. scrapy:集成爬虫框架
  4. pyquery:Python中对jquery的实现,对于熟悉前端的人来说非常容易上手。

BeautifulSoup

BeautifulSoup有多种使用方法,对于查找元素可以使用find_all方法,但是笔者习惯使用select方法(css选择器语法)搜索文档。关于css选择器如果读者对前端足够熟悉的话应该能够轻松上手。经常使用到的标签包括div、span、ul、li、img、a等。我们使用点(.)表示标签的class属性,使用井(#)表示标签的id属性。在使用select方法的时候可以通过他们定位标签数据的位置。关于BeautifulSoup的具体使用方法,读者可以前往官方文档学习。

这里我们以抓取pixabay网站首页图片的url为例:

对于爬虫我建议大家使用chrome浏览器的控制台对页面进行分析(F12调出控制台)。 打开控制台后,选中Elements选项卡我们可以查看网页源代码,通过对网页的分析我们会发现图片的url为img标签的src属性,而img标签的父标签为a,a标签的父标签为div标签,div的父标签为带有class属性为flex_grid和credits的div标签,而该标签的父标签是id属性为gallery的标签。由于id属性是唯一的我们可以以该标签为源点,查找目标标签。

import requests
from bs4 import BeautifulSoup
response = requests.get('https://pixabay.com/en/') #请求pixabay网站
response.encoding = 'utf-8' #设置utf-8编码
html = response.text #网页源代码
soup = BeautifulSoup(html, 'lxml') #使用BeautifulSoup解析网页
imgs = soup.select('#gallery > div.flex_grid.credits > div > a > img') #使用css选择器定位链接,返回结果为包含所有图片标签的列表
for img in imgs:
    print(img['src']) #打印图片标签的src属性

运行结果:

https://cdn.pixabay.com/photo/2018/06/23/16/22/romanesco-3493007__340.jpg
https://cdn.pixabay.com/photo/2018/07/08/14/16/cat-3523992__340.jpg
https://cdn.pixabay.com/photo/2018/05/30/15/31/rustic-3441673__340.jpg
https://cdn.pixabay.com/photo/2016/06/29/09/28/golf-1486354__340.jpg
https://cdn.pixabay.com/photo/2017/11/10/08/10/son-2935723__340.jpg
https://cdn.pixabay.com/photo/2018/07/06/13/30/statue-3520416__340.jpg
https://cdn.pixabay.com/photo/2018/07/08/15/32/dahlia-3524115__340.jpg
https://cdn.pixabay.com/photo/2018/05/07/22/08/sydney-opera-house-3381786__340.jpg
https://cdn.pixabay.com/photo/2018/07/05/23/31/ivy-3519431__340.jpg
https://cdn.pixabay.com/photo/2017/06/05/14/55/glass-2374311__340.jpg
https://cdn.pixabay.com/photo/2018/04/12/11/44/apple-3313225__340.jpg
https://cdn.pixabay.com/photo/2017/09/22/09/48/desert-2774945__340.jpg
https://cdn.pixabay.com/photo/2017/07/12/22/51/couple-2498660__340.jpg
https://cdn.pixabay.com/photo/2016/06/20/03/15/pier-1467984__340.jpg
https://cdn.pixabay.com/photo/2018/01/29/10/40/shower-of-sparks-3115784__340.jpg
https://cdn.pixabay.com/photo/2017/09/06/20/35/massage-2722936__340.jpg
https://cdn.pixabay.com/photo/2018/07/01/20/01/mercedes-3510327__340.jpg
https://cdn.pixabay.com/photo/2018/06/28/15/23/soft-fruits-3504149__340.jpg
https://cdn.pixabay.com/photo/2018/06/28/17/02/water-lily-3504363__340.jpg
https://cdn.pixabay.com/photo/2018/06/29/01/47/piano-3505109__340.jpg

lxml

总的来说使用BeautifulSoup已经能够解决大部分爬虫问题了,但是由于BeautifulSoup的另辟蹊径,独创了一套正则表达式的查询方法导致了爬虫的爬取速度非常的慢,而且BeautifulSoup对于列表项的爬取是非常的糟糕的。但是lxml就不存在着两个问题,lxml由于底层采用c语言代码编写,所以速度上是非常快的。而且由于lxml采用xpath语法解析HTML,对列表项的爬取是非常轻松的。

关于lxml框架和xpath语法,读者可以参看崔庆才的博客

下面使用lxml爬取pixabay网站图片url:

import requests
from lxml import etree
# 获取网页的源代码
response = requests.get('https://pixabay.com/en/')
response.encoding = 'utf-8'
html = response.text
# 解析网页
parser = etree.HTML(html)
for i in range(1,21): #打印前20张图片url
    link = parser.xpath('//*[@id="gallery"]/div[1]/div['+ str(i) +']/a/img/@src')[0]
    print(link) 

运行结果:

https://cdn.pixabay.com/photo/2018/06/23/16/22/romanesco-3493007__340.jpg
https://cdn.pixabay.com/photo/2018/07/08/14/16/cat-3523992__340.jpg
https://cdn.pixabay.com/photo/2018/05/30/15/31/rustic-3441673__340.jpg
https://cdn.pixabay.com/photo/2016/06/29/09/28/golf-1486354__340.jpg
https://cdn.pixabay.com/photo/2017/11/10/08/10/son-2935723__340.jpg
https://cdn.pixabay.com/photo/2018/07/06/13/30/statue-3520416__340.jpg
https://cdn.pixabay.com/photo/2018/07/08/15/32/dahlia-3524115__340.jpg
https://cdn.pixabay.com/photo/2018/05/07/22/08/sydney-opera-house-3381786__340.jpg
https://cdn.pixabay.com/photo/2018/07/05/23/31/ivy-3519431__340.jpg
https://cdn.pixabay.com/photo/2017/06/05/14/55/glass-2374311__340.jpg
https://cdn.pixabay.com/photo/2018/04/12/11/44/apple-3313225__340.jpg
https://cdn.pixabay.com/photo/2017/09/22/09/48/desert-2774945__340.jpg
https://cdn.pixabay.com/photo/2017/07/12/22/51/couple-2498660__340.jpg
https://cdn.pixabay.com/photo/2016/06/20/03/15/pier-1467984__340.jpg
https://cdn.pixabay.com/photo/2018/01/29/10/40/shower-of-sparks-3115784__340.jpg
https://cdn.pixabay.com/photo/2017/09/06/20/35/massage-2722936__340.jpg
https://cdn.pixabay.com/photo/2018/07/01/20/01/mercedes-3510327__340.jpg
https://cdn.pixabay.com/photo/2018/06/28/15/23/soft-fruits-3504149__340.jpg
https://cdn.pixabay.com/photo/2018/06/28/17/02/water-lily-3504363__340.jpg
https://cdn.pixabay.com/photo/2018/06/29/01/47/piano-3505109__340.jpg

进阶

动态数据爬取

占位

百度地图数据爬取

占位

微博数据爬取实战

占位

球探网数据爬取

占位

未完待续。。。

显示 Gitment 评论