不骗你,步步案例,教你一文搞定python爬虫

  • 2019 年 10 月 8 日
  • 筆記

本文转载自数据EDTA

很久以前写了一篇爬虫的文章,把它放在CSDN上(livan1234)没想到点击量竟然暴涨,足以看到大家在数据获取方面的需求,爬虫技术现在已经非常普遍,其用途也非常广泛,很多牛人在各个领域做过相关的尝试,比如:

1)爬取汽车之家数据,利用论坛发言的抓取以及NLP,对各种车型的车主做画像。

2)抓取各大电商的评论及销量数据,对各种商品(颗粒度可到款式)沿时间序列的销量以及用户的消费场景进行分析。

3)还可以根据用户评价做情感分析,实时监控产品在消费者心目中的形象,对新发布的产品及时监控,以便调整策略。

4)抓取房产买卖及租售信息,对热热闹闹的房价问题进行分析。

5)抓取大众点评、美团网等餐饮及消费类网站:各种店面的开业情况以及用户消费和评价,了解周边变化的口味,所谓是“舌尖上的爬虫”。以及各种变化的口味,比如:啤酒在衰退,重庆小面在崛起。

6)58同城等分类信息网站:抓取招商加盟的数据,对定价进行分析,帮助网友解惑。

7)拉勾网、中华英才网等招聘网站:抓取各类职位信息,分析最热门的职位以及薪水。

8)挂号网等医疗信息网站:抓取医生信息并于宏观情况进行交叉对比。

9)应用宝等App市场:对各个App的发展情况进行跟踪及预测。(顺便吹一下牛,我们这个榜单很早就发现小红书App的快速增长趋势以及在年轻人中的极佳口碑)

10)携程、去哪儿及12306等交通出行类网站:对航班及高铁等信息进行抓取,能从一个侧面反映经济是否正在走入下行通道。

11)雪球等财经类网站:抓取雪球KOL或者高回报用户的行为,找出推荐股票

12)58同城二手车、易车等汽车类网站:什么品牌或者型号的二手车残值高?更保值?反之,什么类型的贬值较快?- 二手车,找出最佳的买车时间以及最保值的汽车。

13)神州租车、一嗨租车等租车类网站:抓取它们列举出来的租车信息,长期跟踪租车价格及数量等信息。

14)各类信托网站:通过抓取信托的数据,了解信托项目的类型及规模。其实还有很多数据,不一一列举了。

上次的文章是在讨论移动端的数据获取:https://blog.csdn.net/livan1234/article/details/80850978

本文对爬虫做一个全面的总结,不一定包治百病,但是能治好大部分疾病,希望能够对大家有所帮助:

urllib库

这是一个在爬虫领域绕不开的库,他支持 http 的爬取,几乎可以取到方方面面的内容。

以下面的豆瓣案例做一个简要的解释:

豆瓣小案例:    #!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.request  import re  data= urllib.request.urlopen("https://read.douban.com/provider/all").read()  data = data.decode("utf-8")  pattern = '<div>(.*?)</div>'  mydata = re.compile(pattern).findall(data)  fh = open("出版社.txt", "w")  for i in range(0,len(mydata)):      fh.write(mydata[i]+"n")      fh.close()      常用函数为:      import urllib.request  #1)将第一个参数中的网址,直接下载到filename路径下,爬下来的数据为一个网页。  data= urllib.request.urlretrieve("http://www.hellobi.com",filename="F:python_workspacespider_douban")  #2)清除缓存,清除urlretrieve 等下载时保存的数据  urllib.request.urlcleanup()  #3)爬取页面数据  file= urllib.request.urlopen("http://www.hellobi.com")  #4)返回当环境的信息file.info()  #5)获取当前网页的状态码和网址。  print(file.getcode())  print(file.geturl())

超时设置

由于网络速度或者对方服务器的问题,我们爬取一个网页的时候,都需要设置时间,我们访问一个网页,如果该网页长时间未响应,那么我们的系统就会判断该网页超时了,即无法打开该网页。

有时候,我们需要根据自己的需求,来设置超时的时间值,比如:有些网站会反应快,我们希望2秒没有反应则判断为超时,那么此时,timeout=2即为设置方式,即在 urlopen 中加入 timeout 参数。再比如,有些网站服务器反应慢,那么我们希望100秒没有反应,才判断超时,此时的timeout即设置为100,接下来为大家讲解爬虫超时的设置。

#!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  file = urllib.request.urlopen("http://www.hellobi.com", timeout=10)  for i in range(0, 100):      try:          file = urllib.request.urlopen("http://yum.iqianyue.com", timeout=1)          data = file.read()          print(len(data))      except Exception as e:          print("出现异常:"+str(e))

自动模拟 Http 请求

客户端如果要与服务器端进行通信,需要通过http进行请求,http请求有很多种,我们在此会讲post与get两种请求方式,比如登录、搜索某些信息的时候会用到。

1)处理 get 请求:    #!/usr/bin/env python  # _*_ UTF-8 _*_  import urllib.request  keywd = "python"  #对网址中出现的中文进行相应的编码,得到进行编码之后的中文,后面可以直接使用。  keywd=urllib.request.quote(keywd)  url = "http://www.baidu.com/s?wd"+keywd+"&ie=urf-8&tn=96542061_hao_pg"  #将url 封装为一个请求  req = urllib.request.Request(url)  data = urllib.request.urlopen(req).read()  fh = open("test.txt","wb")  fh.write(data)  fh.close()      2)处理 post 请求:    所谓post请求即为HTML 的 form 中存在 method=“post”的标签,如下文:    <body>    <form action=””,method=”post”>    姓名:<input name=”name” type=”text”/><br>    密码:<input name=”pass” type=”text”/><br>    <input name=”” type=”submit” value=”点击提交”>    </body>

在新浪 login.sina.com.cn 中即可看到,form 为 post 方式。我们只需要 form 表单中的 name 属性即可。

如下图:

#!/usr/bin/env python  # _*_ UTF-8 _*_  import urllib.request  import urllib.parse  url = "http://www.iqianyue.com/mypost/"  #设置对应的表单信息,urlencode中针对代码中的name值。  mydata = urllib.parse.urlencode({  "name":"[email protected]","pass":"123456" }).encode("utf-8")  #将数据转换为请求  req = urllib.request.Request(url, mydata)  #发送请求  data = urllib.request.urlopen(req).read()  fh = open("test_post.txt","wb")  fh.write(data)  fh.close()

爬虫的异常处理

爬虫在运行的过程中,很多时候都会遇到这样或那样的异常。如果没有异常处理,爬虫遇到异常时就会直接崩溃停止运行,下次再次运行时,又会重头开始,所以,要开发一个具有顽强生命力的爬虫,必须要进行异常处理。

异常处理主要是为了增强代码的稳定性。

两者都是异常处理的类,HTTPError是URLError的子类,HTTPError有异常状态码与异常原因,URLError没有异常状态码,所以,在处理的时候,不能使用URLError直接替代HTTPError。如果要替代,必须要判断是否有状态码属性。

接下来我们通过实战讲解:

urlError:

1) 连不上服务器

2) 远程的url不存在

3) 本地没有网络

4) 触发了对应的httpError子类

具体的实战为:

#!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.error  import urllib.request  try:      urllib.request.urlopen("http://blog.csdssn.net")      print("111")  except urllib.error.URLError as e:      if hasattr(e, "code"):          print(e.code)      if hasattr(e, "reason"):          print(e.reason)

爬虫的伪装技术

我们可以试试爬取csdn博客,我们发现会返回403,因为对方服务器会对爬虫进行屏蔽。此时我们需要伪装成浏览器才能爬取。

浏览器伪装我们一般通过报头进行,接下来我们通过实战分析一下。

#!/usr/bin/env python  # _*_ UTF-8 _*_  import urllib.error  import urllib.request  url="http://blog.csdn.net/weiwei_pig/article/details/52123738"  header = ("User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")  #用来添加报头信息  opener = urllib.request.build_opener()  opener.addheaders=[header]  data = opener.open(url).read()  fh = open("test_header","wb")  fh.write(data)  fh.close()

新闻网站爬取

需求:将新浪新闻首页(http://news.sina.com.cn/)所有新闻都爬到本地。

思路:先爬首页,通过正则获取所有新闻链接,然后依次爬各新闻,并存储到本地。

#!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.error  import urllib.request  url="http://blog.csdn.net/weiwei_pig/article/details/52123738"  header = ("User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")  #用来添加报头信息  opener = urllib.request.build_opener()  opener.addheaders=[header]  data = opener.open(url).read()  fh = open("test_header","wb")  fh.write(data)  fh.close()

爬虫防屏蔽手段之代理服务器

#!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.request  import re  url = "http://blog.csdn.net/"  headers = ("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")  #建一个浏览器opener  opener = urllib.request.build_opener()  #将头加入到opener中  opener.addheaders=[headers]  #将opener安装为全局  urllib.request.install_opener(opener)  data = urllib.request.urlopen(url).read().decode("utf-8", "ignore")  pat = '<h3 data-mod="popu_430" data- poputype="feed" data-feed-show="false" data-dsm="post"><a href="(.*?)"'  result = re.compile(pat).findall(data)  for i in range(0, len(result)):      file = str(i)+".html"      urllib.request.urlretrieve(result[i], filename=file)      print("第"+str(i)+"次爬取成功")      如何做代理:        #!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.request  def use_proxy(url, proxy_addr):       proxy = urllib.request.ProxyHandler({"http": proxy_addr})       opener = urllib.request.build_opener(proxy,urllib.request.HTTPHandler)       urllib.request.install_opener(opener)       data = urllib.request.urlopen(url).read().decode("utf-8", "ignore")       return data  proxy_addr = ["110.73.43.18:8123"]  url = "http://www.baidu.com"  data = use_proxy(url, proxy_addr)  print(len(data))

图片爬虫实战

在浏览器爬取时,有时不同的浏览器会有不同的查询结果,解析出不同的源码。

首先在“审查元素”中确定元素的重点字段是哪些,然后再在“源码”中查找对应的图片位置,确定图片 url 的规则。

#!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.request  import re  keyname = "短裙"  key = urllib.request.quote(keyname)  headers = ("User_Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0")  opener = urllib.request.build_opener()  opener.addheaders=[headers]  urllib.request.install_opener(opener)  for i in range(0, 10):      url = "https://s.taobao.com/search?q="+key+"&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&initiative_id=tbindexz_20170306&bcoffset=4&ntoffset=4&p4ppushleft=1%2C48&s="+str(i*44)      data = urllib.request.urlopen(url).read().decode("utf-8", "ignore")      pat = 'pic_url":"//(.*?)"'      imagelist = re.compile(pat).findall(data)      for j in range(0, len(imagelist)):          thisimg = imagelist[j]          thisimgurl = "http://"+thisimg          file = "F:/python_workspace/test/pic/"+str(i)+str(j)+".jpg"          urllib.request.urlretrieve(thisimgurl, filename=file)      在源码解决不了的情况下,需要进行抓包。作业:千图网的爬取(可以通过调试找到报错原因):    #!/usr/bin/env python  # _*_ UTF-8 _*_  # author:livan  import urllib.request  import re  for i in range(1,10):      pageurl = "http://www.58pic.com/piccate/3-153-652-"+str(i)+".html"      data = urllib.request.urlopen(pageurl).read().decode("utf-8", "ignore")      pat = '<a.*?src="(.*?).jpg!"'      imglist = re.compile(pat).findall(data)      for j in range(0, len(imglist)):          try:              thisimg = imglist[j]              thisimgurl = thisimg+"_1024.jpg"              file = "F:/python_workspace/test/pic2/"+str(i)+str(j)+".jpg"              urllib.request.urlretrieve(thisimgurl, filename=file)              print("第"+str(i)+"页第"+str(j)+"个图片爬取成功")          except urllib.error.URLError as e:              if hasattr(e, "code"):                  print(e.code)              if hasattr(e, "reason"):                  print(e.reason)          except Exception as e:              print(e)