Day7.数据采集-爬虫

本文介绍了数据采集的重要性,并探讨了两种方法:八爪鱼采集器和Python爬虫。八爪鱼提供图形化界面,适合初学者,而Python爬虫则允许更高程度的定制。文中详细讲解了Requests库的使用、XPath元素定位以及JSON数据处理,通过实例展示了爬取和解析数据的过程。
摘要由CSDN通过智能技术生成

数据采集

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

通过爬虫获取数据,我们可以有两种方式,一个是通过抓取软件工具,如:火车采集器、八爪鱼、集搜客等,这里推荐使用八爪鱼,它可以提供一个免费的版本使用;还有一种方式是通过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访问的话,代码可以写成下面这样的:

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

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

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中的所有列表项目,可以采用下面这段代码:

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对象的代码,可以运行下这个程序的结果。

import json
jsonData = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
input = json.loads(jsonData)
print(input)

案例实操:

爬取公开手机型号 机型价位数据。

用于后续分析 手机性能特点。

再次强调,本案例仅限学习分享。不用于任何商业用途。


#!/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_='p-more').attrs['href']
                        except:
                            url_param = soup2.find('div', class_='info-list-02').find('a', class_='p-more').attrs['href']
                    except:
                        url_param = soup2.find('div', class_='p-content').find('a',class_='_j_MP_more p-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)

运行结果如下

写在后面:

今天的爬虫是不是很有意思~

如果有问题,但是也请耐心的调试~

记得打卡,在群里分享你的代码和笔记~

换一种方式能不能实现呢?

好文章,我在看❤
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值