前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Day7.数据采集-爬虫

Day7.数据采集-爬虫

作者头像
DataScience
发布2020-06-04 15:03:49
9560
发布2020-06-04 15:03:49
举报
文章被收录于专栏:A2DataA2Data

数据采集

我们进行数据分析以及挖掘时,前提条件就是需要有数据;如果在公司里作业,我们可以从数据库中导入数据,但同时我们也可以对采集数据来进行分析。采集数据最常用就是我们听到的爬虫,通过爬虫爬取网页上的信息,如购物网站用户评论进行产品调研,微博留言等来进行舆论分析,那么今天我就来了解如何使用爬虫采集数据。

通过爬虫获取数据,我们可以有两种方式,一个是通过抓取软件工具,如:火车采集器、八爪鱼、集搜客等,这里推荐使用八爪鱼,它可以提供一个免费的版本使用;还有一种方式是通过Python编程抓取网页信息。

八爪鱼采集数据

八爪⻥的使用简便,提供图形化的界面,基本上不需要编写代码,除了在正则表达式匹配的时候会用到XPath。XPath的英文是XML Path Language,也就是XML的路径语言,用来在XML文件中寻找我们想要的元素,xml文件用来存放描述和存放数据,因而八爪⻥可以使用XPath帮我们更灵活地定位我们想要找的元素。

在百度搜索下载”八爪鱼采集器“下载安装,官方在教程与帮助中提供的内容也非常丰富,在这里我们就不演示了,需要使用的时候我们根据官网教程学习,上手简单。基本流程是输入网页,设计流程和启动采集。在流程设计中设置好关键词,软件搜索后,设置翻页并提取数据,启动采集;此外八爪鱼还提供很多模板,帮助快速设置需要爬取的内容。

Python爬虫

使用八爪鱼采集器虽然上手速度快,但是也存在一些问题,比如运行速度慢、定制化程度不高,通过爬虫可以解决这一问题。

爬虫实际上是用浏览器访问的方式模拟了访问网站的过程,整个过程包括三个阶段: 打开网⻚、提取数据和保存数据。三个阶段都有对应的工具可以使用。在“打开网⻚”这一步骤中,可以使用 Requests 库访问⻚面,得到服务器返回给我们的数据,这里包括HTML⻚面以及JSON数据。“提取数据”这一步骤中,主要用到了两个工具;针对HTML⻚面,可以使用 XPath 进行元素定位,提取数据;针对JSON数据,可以使用JSON进行解析。在最后一步“保存数据”中,使用 Pandas 保存数据,导出CSV文件。下面我来介绍下这些工具的使用:

Requests访问⻚面

Requests是Python HTTP的客户端库,编写爬虫的时候都会用到,编写起来也很简单。它有两种访问方式:Get和Post。这两者最直观的区别就是:Get把参数包含在url中,而Post通过request body来传递参数。

假设我们想访问淘宝,那么用Get访问的话,代码可以写成下面这样的:

代码语言:javascript
复制
r = requests.get('http://www.taobao.com')
# 代码里的“r”就是Get请求后的访问结果,然后我们可以使用r.text或r.content来获取HTML的正文

如果我们想要使用Post进行表单传递,代码就可以这样写:

代码语言:javascript
复制
r = requests.post('http://xxx.com', data = {'key':'value'})
# data是传递的表单参数,data的数据类型是字典
XPath定位

XPath是XML的路径语言,实际上是通过元素和属性进行导航,帮我们定位位置。它有几种常用的路径表达方式。

表达式

含义

node

选取node节点的所有子节点

/

从根节点选取

//

选区所有当前节点,不考虑他们的位置

.

当前节点

..

父节点

@

属性选择

|

或,两个节点的合计

text()

当前路径下的文本内容

一些简单的例子:

  • 1.xpath(‘node’) 选取了node节点的所有子节点;
  • 2.xpath(’/div’) 从根节点上选取div节点;
  • 3.xpath(’//div’) 选取所有的div节点;
  • 4.xpath(’./div’) 选取当前节点下的div节点;
  • 5.xpath(’..’) 回到上一个节点;
  • 6.xpath(’//@id’) 选取所有的id属性;
  • 7.xpath(’//book[@id]’) 选取所有拥有名为id的属性的book元素;
  • 8.xpath(’//book[@id=“abc”]’) 选取所有book元素,且这些book元素拥有id= "abc"的属性;
  • 9.xpath(’//book/title | //book/price’) 选取book元素的所有title和price元素。

XPath可以提供超过100个内建函数,来做匹配。网页上定位的节点,几乎都可以使用XPath来选择。使用XPath定位,会用到Python的一个解析库lxml。这个库的解析效率非常高,使用起来也很简便,只需要调用HTML解析命令即可,然后再对HTML进行XPath函数的调用。

比如我们想要定位到HTML中的所有列表项目,可以采用下面这段代码:

代码语言:javascript
复制
from lxml import etree
html = etree.HTML(html)
result = html.xpath('//li')

HTML页面中涉及到的元素如列表List缩写是li;nide,div也是html中的知识。爬取网页需要我们对网页的知识有一定的了解,学习起来也不难。对于HTML的知识不会涉及,如果需要使用以后我可以再搜索相关知识进行学习,主体是了解以及掌握基本的爬虫知识。

JSON数据

JSON是一种轻量级的交互方式,在Python中有JSON库,可以让我们将Python对象和JSON对象进行转换。为什么要转换呢?原因也很简单。将JSON对象转换成为Python对象,我们对数据进行解析就更方便了。

方法

含义

json.dumps()

将Python对象转换成Json对象

json.loads()

将Json对象转换成Python对象

这是一段将JSON格式转换成Python对象的代码,可以运行下这个程序的结果。

代码语言:javascript
复制
import json
jsonData = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
input = json.loads(jsonData)
print(input)

案例实操:

爬取公开手机型号 机型价位数据。 用于后续分析 手机性能特点。 再次强调,本案例仅限学习分享。不用于任何商业用途。

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'JackFeng'

# @Time   : 2020/6/1 23:56
# @Author : JackFeng
# @FileName: PySpiderPhone.py
# @Software: PyCharm
# @Blog   :http://www.a2data.cn/


import requests
from bs4 import BeautifulSoup
import re
import time
import random

"""
爬取中关村网站 手机型号价位 分析手机性能
  1、公开网站
  2、本爬虫仅限于学习
  3、不做任何商业用途
  4、任何利益与本文无关
"""

headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
try:
   with open('./DataScience.txt', 'a', encoding='utf-8') as file:
       for y in range(0,29):
           url = 'http://detail.zol.com.cn/cell_phone_advSearch/subcate57_1_s8379-s8010_1_1__{}.html'.format(str(y))
           print(url)
           data = requests.get(url,timeout=10).text  # 下载网页的text内容
           soup = BeautifulSoup(data,'html.parser')  # lxml 所有手机列表
           # print(ss_1)
           time.sleep(random.randint(0, 8))

           header='http://detail.zol.com.cn'
           for j in range(0,30):
               link_a = soup.find("div",class_='list_box').find("ul",class_='result_list').find_all('dl',class_='pro_detail')[j]
               index=link_a.find('dt').find('a').attrs['href']
               phone_url=header+index
               # print(phone_url)
               data2 = requests.get(phone_url, timeout=10).text  # 下载网页的text内容
               soup2 = BeautifulSoup(data2, 'html.parser')  # lxml 每个手机详情页面
               name=soup2.find('div',class_='product-model page-title clearfix').find('h1').get_text()
               # print(name)
               try:
                   model=soup2.find('div', class_='product-model page-title clearfix').find('h2').get_text().replace("别名:","")
               except:
                   model='None'
               # print(model)
               try:
                   try:
                       price = soup2.find('div', class_='product-price-box').find('b',class_='price-type').get_text()
                   except:
                       price = soup2.find('div', class_='product-detail').find('b', class_='price-type').get_text()
               except:
                   price = soup2.find('div', class_='pro-zhibo-infos').find('span',class_='price-type').get_text()
               # print(price)
               print("{},name:{},model:{},price:{}".format(j,name,model,price))

               # 详细参数列表链接
               if price in ('概念产品','即将上市'):   # 这类手机上市之后再爬
                   pass
               else:
                   try:
                       try:
                           url_param=soup2.find('div', class_='info-list-01').find('a',class_='section-more').attrs['href']
                       except:
                           url_param = soup2.find('div', class_='info-list-02').find('a', class_='section-more').attrs['href']
                   except:
                       url_param = soup2.find('div', class_='section-content').find('a',class_='_j_MP_more section-more').attrs['href']
                   url_param=header+url_param
                   # print(url_param)
                   data_param = requests.get(url_param, timeout=10).text  # 下载参数表格所在页面内容
                   soup3 = BeautifulSoup(data_param, 'html.parser')  # lxml
                   table0=soup3.find('div',class_='detailed-parameters').find_all('table')[0]
                   param_list0=table0.find_all('tr')
                   # print(param_list0)
                   for i in param_list0:
                       try:
                           head=i.find('th').find('span').get_text()
                           # print(head)
                           if head in ('发布会时间','上市日期'):
                               sale_time = i.find('td').find('span').get_text()
                               # print("{}:{}".format(head,sale_time))
                           elif head in ('操作系统','出厂系统内核'):
                               os = i.find('td').find('span').get_text()
                               # print("{}:{}".format(head,os))
                           elif head in ('手机类型'):
                               phone_type = i.find('td').find('span').get_text()
                               # print("{}:{}".format(head,phone_type))
                           else:
                               pass
                       except:
                           pass
                   try:
                       print(os)
                   except:
                       os='None'

                   table1 = soup3.find('div', class_='detailed-parameters').find_all('table')[1]
                   param_list1 = table1.find_all('tr')
                   for i in param_list1:
                       try:
                           head = i.find('th').find('a').get_text()
                           if head =='主屏尺寸':
                               pattern = re.compile(r'\d*\S\d*(英寸)')
                               si = i.find('td').find("span").get_text()
                               size = re.search(pattern, si).group(0)
                               # print("{}:{}".format(head,size))
                           elif head=='主屏分辨率':
                               pattern = re.compile(r'\d*\S\d*(像素)')
                               reso = i.find('td').find("span").get_text()
                               resolution=re.search(pattern, reso).group(0)
                               # print("{}:{}".format(head,resolution))
                       except:
                           pass
                   table2 = soup3.find('div', class_='detailed-parameters').find_all('table')[2]
                   param_list2 = table2.find_all('tr')
                   for i in param_list2:
                       try:
                           head = i.find('th').find('a').get_text()
                           pattern = re.compile(r'\d*(GB)')
                           if head =='RAM容量':
                               ram1 = i.find('td').find("span").get_text()
                               ram = re.search(pattern, ram1).group(0)
                               # print("{}:{}".format(head,ram))
                           elif head=='ROM容量':
                               rom1 = i.find('td').find("span").get_text()
                               rom = re.search(pattern, rom1).group(0)
                               # print("{}:{}".format(head,rom))
                       except:
                           pass
                   try:
                       print(ram)
                   except:
                       ram='None'

                   try:
                       print(rom)
                   except:
                       rom = 'None'

                   print("手机:{}\t机型:{}\t价格:{}\t上市时间:{}\t操作系统:{}\t屏幕尺寸:{}\t像素:{}\t运行内存:{}\t手机内存:{}\t手机类型:{}\n".format(name,model,price,sale_time,os,size,resolution,ram,rom,phone_type))
                   file.write('手机:{}\t机型:{}\t价格:{}\t上市时间:{}\t操作系统:{}\t屏幕尺寸:{}\t像素:{}\t运行内存:{}\t手机内存:{}\t手机类型:{}\n'.format(name,model,price,sale_time,os,size,resolution,ram,rom,phone_type))
               print("===========第 {} 个机型信息获取完毕=========".format(j))
               # time.sleep(random.randint(0, 8))
           print("============第 {} 页信息爬取完毕==============".format(y))
       print("******************************所有信息爬取完毕***********************************")
   file.close()
except requests.exceptions.ConnectionError as e:
   print('Error', e.args)

运行结果如下

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DataScience 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据采集
    • 八爪鱼采集数据
      • Python爬虫
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档