初识python
作为一位前端开发人员,一直以来,接触最多的也都是html,css,js;有时候会需要搭建一些node服务器,写一些node后台代码,仅此而已;
而python,只是在以前使用某些软件时,需要python环境,就安装到了电脑,然后,从来都没有真正的接触过它;
随着数据分析、深度学习、机器学习的发展,也让我开始了python的学习之旅;虽然都说,不管是什么语言,基本上都是相通的;但是对于一种你从未接触过的语言,基础,还是非常重要的;所以,我还是默默的打开了浏览器,在百度中搜索了“python基础教程”,最后找到了Python 基础教程 | 菜鸟教程,在这里面,有环境的搭建、基本语法、数据类型、常用函数等非常基础的教程,我觉得非常适合我这种从来没有接触过的人;随后,我花了几个小时的时间,将这里面基础教程的所有内容看了一遍,在看的过程中,也跟着做了一些练习;
虽然说,看了基础教程,也顶多你大概能够使用python进行一些简单的运算而已;而作为开发人员,都明白一个道理,最好、最快的学习一种语言的方式当然是从一个简单的项目开始,自己能够从头开始做一个自己觉得有意思但是难度不是很大的东西,这样,不仅能够让自己能够更快的去理解这种语言,而且,会使自己更有学习的动力和信心;因此,我开始了一个简单的网站的数据爬取的实现,因为对于我这种前端出生的人来说,与浏览器打交道,与网页打交道,相对来说,简单很多;
开始
首先,我肯定不知道从何处开始,因此,我只能继续百度“python 爬虫”;最后找到了这篇文章“Python爬虫实战二之爬取百度贴吧帖子”,为什么选择它呢?只有一个原因,在它的文章最后,有完整的代码,我没去看里面的描述,而是,直接用sublime直接创建了一个名为
$ pachong.py
的文件,然后将代码全部拷贝进去(虽然说可能代码根本运行不通);
随后,我开始了我的爬虫之旅,一开始,我就直接在拷贝的代码基础上直接修改,而不同的是它爬取的是百度贴吧,我爬取的是汽车之家。然后代码就在这儿pachong.py(由于代码较多,就不直接贴出来了,有兴趣的,可以直接点链接进github查看);在这里面有个很坑的地方,它的所有筛选自己需要数据的方式是通过正则匹配的方式实现的,而我什么也不知道的跟着学着,也使用正则,让我为了从整个html中筛选自己需要的,花费了太多的时间,而且效果一般;但是后面才发现,已经有很完善的专门匹配页面内容方式的Python库BeautifulSoup(这是它的中文文档链接);
使用BeautifulSoup重写
当发现了BeautifulSoup之后,简单看了一篇BeautifulSoup教程,看完之后,如获至宝,因为它的使用方式里面有很多和前端里面去获取元素,获取节点有异曲同工之妙;而我最喜欢使用的,是里面的“CSS选择器”方式,简直和前端使用jquery一模一样,比如:
通过标签名查找
print soup.select('p')
通过类名查找
print soup.select('.sister')
通过 id 名查找
print soup.select('#link1')
......等等;
因此,我果断选择使用BeautifulSoup对上面最初的版本进行重写,尤其是在对内容的筛选;而这一次,我选择了去爬取“蚂蜂窝”的游记;
作为前端开发的我,对于Chrome DevTools的使用,简直是易如反掌;所以很容易就可以找出怎么去获取自己需要的内容(到底是用类名查找还是id查找,或者是什么组合查找),对于Chrome DevTools不是很熟的同学,可以看下这个感觉挺全的;
以爬取蚂蜂窝的游记为例,比如这一篇:
1、通过request获取网页
request = urllib2.Request('http://www.mafengwo.cn/i/6958115.html')
response = urllib2.urlopen(request)
soup = BeautifulSoup(response.read().decode('utf8').encode('utf8'), "html.parser")
2、获取标题
return soup.select('.headtext')[0].string
3、获取文章html内容
article = soup.select('.vc_article')[0]
html = article.prettify()
4、获取用户信息(如头像,名称),这个稍微要复杂一些,因为它在上面第一步直接请求的html页面里面是找不到的,然后通过Chrome DevTools中的Network功能,可以找到拉取这些信息的请求地址“https://www.mafengwo.cn/note/pagelet/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249”,细心的你可能会发现,在这个请求中有个“6958115”,这个不就是第一步里面页面的结尾数字吗,我们可以理解为id;那么,这个请求就是通过
开始
https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%226958115%22%7D&_=1492868086249](https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%22
加上 id
6958115
加上结尾
%22%7D&_=1492868086249
最后组合成的一个完整的url,然后通过第一步请求后,将获取的数据通过正则的方式,只去html部分,然后通过BeautifulSoup取出对应的头像,姓名;
//其中article_id就是上面说的第一步链接结尾数字“6958115”
userInfoURL = 'https://www.mafengwo.cn/note/__pagelet__/pagelet/headOperateApi?callback=jQuery1810173556954190627_1492868085919¶ms=%7B%22iid%22%3A%22' + article_id +'%22%7D&_=1492868086249'
request = urllib2.Request(userInfoURL)
response = urllib2.urlopen(request)
result = response.read()
pattern = re.compile('jQuery.*?\(')
pattern1 = re.compile('\)\;')
result = re.sub(pattern, "", result)
result = re.sub(pattern1, "", result)
result = eval(result)
html = result['data']['html']
soup = BeautifulSoup(html, "html.parser")
//头像
avatar = soup.select('.per_pic img')[0]['src']
//用户名
name = soup.select('.per_name')[0]['title'].encode('utf-8')
搭建服务器
在你爬取到数据之后,你总会希望能够在界面上能够真正的展示出来,所以,我就决定使用python搭建一个简单的本地服务器;因为通过学习python的时候发现菜鸟教程确实比较适合我这种菜鸟的,所以就看完了Django 菜鸟教程,这个教程虽然简单,但是全面,对我做一个简单服务器来说,足够了;然后,就通过这个教程搭建了一个简单的python服务器,在浏览器中,就可以看到自己爬取的页面了,具体可见整个项目代码
mongodb 数据保存、使用
在你爬取一篇过后,肯定是不会停止的,所以,我们总会找个能够保持我们爬取数据的地方(数据库);因为以前在进行node开发的时候,使用过mongodb,所以就选择了它作为我保存数据的地方;使用python来操作mongodb,我没有找到相关比较好的文章,所以就直接参考的PyMongo 3.4.0 documentation这个api文档,这个夜比较详细和简单,对于我来说够用了;它包含了如何和mongodb链接、如何获取数据库,如何获取数据库里面的collection,如何查找、添加数据等等;其实很简单:
from pymongo import MongoClient
import settings
#连接mongodb
client=MongoClient('mongodb://127.0.0.1:27017/')
//获取数据库
db = client[settings.DBNAME]
// 获取数据库里面的collection
def getCollection(collection):
if(collection):
return db[collection]
else:
return None
数据保存的代码就不贴出来了,有兴趣可以看这个models.py.
自动爬取所有游记
当你想爬取更多的时候,你肯定不希望是自己手动去查找一个一个的id,然后手动爬取,所以,我们就希望有更加自动化的爬取方式;对于这种方式,必须得解决下面两个问题:
- 获取所有的游记id(就形如“6958115”这种的东西)
- 解决因为自动化请求过快,过于频繁,导致“服务器拒绝访问”的问题
第一个,获取所有id;当你使用Chrome DevTools Network去看列表下一页的请求的时候,你会发现,它访问了一个“http://www.mafengwo.cn/note/pagelet/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522¶ms=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A1%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862”这样的链接,它也是和上面获取用户信息一样分成三个部分,其中有个第几页的参数“page=1”,这里面就返回了所有的列表的html代码,其中包括我们需要的id;
url = 'http://www.mafengwo.cn/note/__pagelet__/pagelet/recommendNoteApi?callback=jQuery18103478581123017468_1492999122522¶ms=%7B%22type%22%3A0%2C%22objid%22%3A0%2C%22page%22%3A'+str(page)+'%2C%22ajax%22%3A1%2C%22retina%22%3A0%7D&_=1492999206862'
request = urllib2.Request(url)
response = urllib2.urlopen(request)
result = response.read()
pattern = re.compile('jQuery.*?\(')
pattern1 = re.compile('\)\;')
result = re.sub(pattern, "", result)
result = re.sub(pattern1, "", result)
result = eval(result)
html = result['data']['html']
html = html.replace('\\/', '/')
html = html.decode('string-escape')
soup = BeautifulSoup(html, "html.parser")
links = soup.select('.tn-item .tn-image a')
_ids = []
for link in links:
_id = link['href'].replace('/i/', '').replace('.html', '')
_ids.append(_id)
然后我们就会根据每一页获取的id循环自动跑爬取对应页面数据并保存至数据库,每跑完一页的数据,就会递归跑下一页数据,直到最后一页
只是在跑的过程中,就会遇到第二个问题,因为访问过快、过于频繁而导致服务器拒绝访问,在这儿我没有通过网上说的各种高端的方式,而是采用的比较笨重的方式,就是在跑完一个请求后,让程序休息几秒钟,再去进行下一个请求,我将时间设置的10秒,目前没有拒绝访问的问题,只是跑起来比较慢一些;
import time
.....
time.sleep(10)
.....
对于上面的所有代码,如果感兴趣的,整个项目代码可以在这儿(github)找到.
目前,爬取就差不多只有这些,后面会慢慢继续去完善和学习;对于我来说,python的学习之路也才刚刚开始;
网友评论