首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

数据分析师的编程之旅——Python爬虫篇(3)用基础知识练练手

作者:李禹锋,重庆芝诺大数据分析有限公司数据挖掘工程师。

昨天写了一个网站的整站爬虫,电脑一直处于高负荷运行的状态,没来得及更新文章。今天就以前几篇的基础知识,来进行爬虫练手。纯粹的看是学不会的,多实际操作,运行运行别人的代码,再修改别人的代码很快就能上手,日本著名数学家小平邦彦也曾说过模仿加改良等于创新嘛。

01

百度新闻爬虫小DEMO

第一个DEMO拿百度新闻为例,需求是以python爬虫为关键词,爬取百度新闻搜索的所有链接、标题和简介的内容。

首先第一步要思考一个问题,百度新闻是如何进行翻页操作的?在互联网上,翻页几乎算得上是最常见的操作之一了,当然方法也多种多样,甚至不少网站就以翻页的控制来进行反爬虫的控制。

不过我们以百度作为正式爬虫的第一个DEMO其实就是因为百度搜索没啥反爬虫。翻页的操作也是最简单的一种——通过调整发送的参数来进行页码的调整。下面来介绍一下什么是URL,如何来写参数。

例如在百度新闻中搜索了“python爬虫之后”,url变为了如下。

看似是一堆稀奇古怪的东西,但是一个词一个词挨着来看其实很简单。

开头的http://代表的是协议名,之前也曾说过协议有很多,目前只需了解http和https两种即可。

接下来的news.baidu.com代表的域名,可以理解为一个域名对应着一个公网的IP地址(需要找到这个对应表就需要DNS进行解析,不过这一部分只需了解即可)。

之后是一根斜线和ns,代表的是对方网站的路由,暂时可以简单的想象成是对方网站所在服务器的文件路径,就像是我们在windows的文件路径一样,在A文件夹之下的B文件夹下的C文件可以写成 A/B/C 。

再然后就是关键了,一个问号开头,后面以&符号进行拼接,每一个小块都是以 变量名=变量值 的形式呈现,这里的每一个小块都是一个参数。当然也并不是需要清楚所有的参数有什么用,想要了解的童鞋可以自行尝试。我们只需要关注最核心的一些参数(如何进行翻页的参数)。

上面那种形式是点击了百度一下之后的URL,虽然也有规律性,但这里给大家一个小技巧,在针对这种通过参数来进行翻页的网站进行爬虫时,先翻到后面的页数再倒回第一页,这样URL会变得更加规律一些。

搜索第一页的URL变为了如下

第二页URL

第三页URL

第四页URL。。。

发现规律了吗?其他的部分都没有变化,变化的只有pn一个参数,每一页有20条新闻,所以每翻一页url中的pn参数就加20(可以尝试改改rn参数,看看是什么效果,改成50试试)。

而URL在python中是字符串,那么通过字符串的拼接即可做到循环每一页的内容(学会找URL规律的方法,还是有不少网站是通过URL的参数进行翻页控制的)

那么下面就结合前两篇的内容,直接上代码了。

from urllib.request import Request,urlopen

from scrapy import Selector

for i in range(7): #直接看的有7页内容,偷个懒

url = "http://news.baidu.com/ns?word=python%E7%88%AC%E8%99%AB&pn="+str(i*20)+"&cl=2&ct=1&tn=news&rn=20&ie=utf-8&bt=0&et=0"

req = Request(url=url,headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'})

html = urlopen(req).read().decode('utf-8')

nodes = Selector(text=html).xpath('//div[@id="content_left"]/div[3]/div')

for j in range(len(nodes)):

res = {

'title':nodes[j].xpath('h3/a/text()').extract(),

'link_url':nodes[j].xpath('h3/a/@href').extract(),

'content':'div/div[2]/text()'

}

print(res)

02

CSDN小DEMO

如上小DEMO就实现了一个循环翻页爬虫的功能,下面的小DEMO是一个两层爬虫,即第一次爬虫获取到相关的链接,再循环爬取第一次获取到的链接。以CSDN搜索Python爬虫为例,搜索所有CSDN中关于Python爬虫的文章(还有视频教程以及下载资源等,这部分需要排除)。

目前还是以偷懒的方式来写,搜索后CSDN显示共有179560条结果,每页显示20条,即共有8978页(先这样理解吧,其实其中有不少是重复的,假设全部为不重复的。而且最关键问题在于,在这么多条结果的时候绝大部分网站的后台逻辑并不支持,因为没有几个真正的用户会看那么多页的内容,CSDN就是这样,普通的操作只提供前20页的内容,即400条数据)

代码如下(自行运行时需要运行一些时间,8978页+179560页,该爬虫需要发送188538个请求,也需要解析这么多个页面,目前还未涉及多线程、多进程爬虫,也还未涉及分布式集群爬虫,电脑性能不太好的童鞋慎用)

from urllib.request import Request,urlopen

from scrapy import Selector

from re import findall

for i in range(1,8979):

url='http://so.csdn.net/so/search/s.do?p='+str(i)+'&q=python%E7%88%AC%E8%99%AB&t=&o=&s=&u=&l=&f='

req = Request(url=url,headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'})

html = urlopen(req).read().decode('utf-8')

#获取到所有链接

links = Selector(text=html).xpath('//dl[@class="search-list" or @class="search-list J_search"]/dt/a/@href').extract()

#循环当前搜索页的所有链接

for link in links:

#运用正则表达式进行判断,该链接是否为文章(文章的URL中有/article/details/)

if findall(r'/article/details/',link):

req_link = Request(url=link,headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'})

html_link = urlopen(req_link).read().decode('utf-8')

#因CSDN文章含有HTML的格式,故可直接获取整篇文章的HTML,之后再行清洗整合在自己网站的页面中

article = Selector(text=html_link).xpath('//article').extract()

print(article)

03

初步优化CSDN小DEMO

以上两个案例的代码都是按照着纯流程化来书写的,可以发现其中有着不少重复代码,特别是CSDN的DEMO,例如发送请求时,变动的仅仅是URL,进行解析时,变动的仅仅是XPATH。故我们可以使用函数封装的方式来进行初步的代码优化。详细如下。

from urllib.request import Request,urlopen

from scrapy import Selector

from re import findall

def parse(url,xpath):

req = Request(url=url,headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'})

html = urlopen(req).read().decode('utf-8')

return Selector(text=html).xpath(xpath).extract()

def main():

for i in range(1,8979):

url = 'http://so.csdn.net/so/search/s.do?p='+str(i)+'&q=python%E7%88%AC%E8%99%AB&t=&o=&s=&u=&l=&f='

links = parse(url=url,xpath='//dl[@class="search-list" or @class="search-list J_search"]/dt/a/@href')

for link in links:

if findall(r'/article/details/',link):

article = parse(url=link,xpath='//article')

print(article)

main()

放假通知

地球不爆炸,我们不放假

宇宙不重启,我们不休息

人生。。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180209G0EVU400?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券
http://www.vxiaotou.com