基于Scrapy框架对二手车数据进行挖掘
基于个人的项目来把自己的一些经验分享给大家,其中个别图片和文字是来源于互联网,就不一一标注了。
不保证完全正确。
理论知识及框架、包介绍
Scrapy框架:爬取数据,提取结构性数据的应用框架
它包括引擎、调度器、下载器、爬虫(Spider)、Item容器五大组件。
可以应用在数据挖掘、信息处理或存储历史数据等一系列的程序中
最初是为了页面抓取所设计,也可以应用在获取API所返回的数据(例如AAMS)或者通用的网络爬虫
组件之间通过数据流通讯(绿色部分)
Spider->Engine->Scheduler->Downloader:(request数据)
Downloader->Engine->Spider->ItemPipeline:(response数据)
一、Spider:存放爬虫程序,包括回调函数(处理response数据函数)
(1)需要request的网页放在Spider,然后提供给引擎
(6)接受引擎发送的数据,用回调函数并分析
二、引擎:Scrapy的核心,数据所有组件之间的数据流动。
(2)将Spider发过来的网页(request)给调度器
(5)将下载器发送的数据再传给Spider,供其分析
三、调度器:负责调度
(3)从引擎接受网页(request),再转给下载器。
四、下载器:下载网页内容
(4)获得调度器发过来的网页,提取其中的数据(response),再发给引擎
五、item容器:定义结构性数据,并对数据进行数据库存储
(7)负责处理 Spider提取出来的Item(容器,存放需要的内容) 进行存储化(如存放到数据库或文件)
其他中间件:提供一个简便的机制,通过插入一个定义的代码来扩展Scrapy的功能
下载器中间件:特定hook(钩子),用于处理下载器发送到引擎的response
Spider中间件:处理引擎和Spider交互的一个hook,将引擎出来的reponse数据过滤和一些额外的操作,再给Spider
同时接受SPiders的输出(request请求和item的输出) 并过滤
实战
1、二手车网站选取:二手车之家
尝试找了一些网站,最终找到二手车之家,这个网站的数据信息比较全面。
相对于人人二手车网站,其信息更加正确,人人二手车有相当数量的假数据和脏数据,后期会造成很大的处理和分析困难。
相对于瓜子二手车网站,其反爬虫机制还不健全,利于我们对数据进行有效及时的爬取和保存。
对于以上两个网站,针对其设置的反爬虫机制,我们需要改变User Agent 和设置访问间隔,这既会造成我们代码编写困难,也会导致数据收集的速度大大下降。
2、编写爬虫项目
2.1 创建项目
1.首先我们在cmd窗口下,在桌面创建我们的scrapy项目model:
C:\Users\15650>cd desktop
C:\Users\15650\Desktop>scrapy startproject model
2(可选,帮助我们自动生成爬虫文件,也可手动设置)(爬虫名one 默认爬虫网站 taoche.com);
C:\Users\15650\Desktop>cd model
C:\Users\15650\Desktop\model>scrapy genspider one che168.com
2.2 编写爬虫程序
思想:基于BFS爬取策略,爬取二手车数据。
首先Scrapy自动urllib.request网页然后把response网页数据传给回调函数。
回调函数对整个html网页内容,然后使用xpath提取网页内容中所需要的信息。
包括:二手车名称,二手车价格(万元),比新车省的价格(万元),商家名称,行驶里程(万公里),首次上牌时间,’
‘所在地,发布时间,年检到期日期,保险到期日期,排放标准,过户次数,’
'维修保养,车辆说明,发动机,变速器,车辆级别,颜色,燃油标号,驱动方式,采集网址
然后把所有信息都存放到ITem数组,再提交给pipeline,然后存储到数据库中。
2.3数据清理
将数据库中文件保存到本地Excel文件,然后利用Jyputer Notebook读取并进行预处理。
包括去重和数据标准化。
数据清洗,并将正常数据分为测试集(500个)和训练集(测试集合以外的所有)。
包括:删除重值、删除网址和说明、滤除缺失数据、删除所有带"-"的行、把时间戳转换为正常字符串,将上牌时间戳转为正常时间,将未上牌删除、删除属性值的前后空格。
并删除异常价格。
数据清洗之后,将正常数据分为测试集(500个)和训练集(测试集合以外的所有),然后在保存为本地文件。
2.4数据线性分析
利用面向对象的思想来进行二手车数据属性的线性关系,包括属性的占比:例如城市占比、不同车型占比;
和属性线性关系的分析:比如价格和车型的关系,降价和行驶里程的问题。
利用pyecharts显示出来。
其中遇到的未知原因错误有:
python-关于报错cannot import *** from pyecharts的问题
可以尝试先卸载,然后换个镜像重新安装:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyecharts
重装完再imoprt pyecharts可能出现no module named 'pyecharts_snapshot’的报错:
这时同样安装上面的方法安装pyecharts_snapshot即可:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyecharts_snapshot
具体原因不详,但是实测有效,大神看到解答一下!
机器学习初探索
利用KNN算法对价格范围作一个预测,实现机器学习的初步探索。
KNN(K近邻算法):最简单的分类算法
K近邻(k-Nearest Neighbor,KNN)分类算法的核心思想是如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
KNN算法可用于多分类,KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,作为预测值。
实战-初探索(dmoz,开放式分类目录网站,也就是导航网站)
download book和resource
使用Scrapy抓取一个网站一共需要四个步骤
1):创建一个Scrapy项目
2):定义Item容器
3):编写爬虫
4):存储内容
1.创建Scrapy新项目:
cmd窗口下
cd desktop
scrapy startproject 新项目名
配置文件:scrapy.cfg
子文件夹:存放模块的代码
items、pipeline对应框架图中的两个同名组件、settings(设置文件)、子文件夹spiders(对应同名流程图中组件)
2.定义Item容器
item:保存爬取到的数据的容器,使用方法和python字典类似,并且提供了额外保护机制来避免拼写错误导致的未定义字段的错误
首先对需要获取的数据进行建模(资源名字、资源超链接、资源描述):在items.py里面建立相应的字段
# name = scrapy.Field()
name:需要建立字段的名字
scrapy.Field():需要的占位符
item容器:
import scrapy
class DmozItem(scrapy.Item):
title = scrapy.Field()
link = scrapy.Field()
desc = scrapy.Field()
3.编写爬虫(编写Spiders类)
Spiders:用户编写用于从网站上爬取数据的类
包含一个用于下载的初始url,然后是如何跟进网页中的链接以及如何分析页面中的内容,还有提取生成item方法
在cmd窗口项目中:scrapy genspider dmoz dmoz.org
自动在spiders文件中生成dmoz.py
或者手动生成
dmoz.py代码
import scrapy
class DmozSpider(scrapy.Spider):
name = 'dmoz' #用来确认蜘蛛的名字
allowed_domains = ['dmoztools.net'] #蜘蛛要爬取的范围(只会爬该列表里面的链接)
start_urls = [
'http://www.dmoztools.net/Computers/Programming/Languages/Python/Books/',
'http://www.dmoztools.net/Computers/Programming/Languages/Python/Resources/'
]#需要开始爬取的网址
def parse(self, response): #分析的方法 筛选出item对应的数据
#reponse.url应该是列表
filename = response.url.split("/")[-2] #保存成两个文件(使用split分片,截取倒数第二个字符串)
with open(filename,'wb') as f:
f.write(response.body)
#在根目录生成两个网页的源代码
爬取:
项目cmd窗口:scrapy crawl dmoz
调用爬虫dmoz 去工作
流程:
1)需要request的网页存放在Spider,然后提供给引擎
2)引擎将Spider发送过来的网页(request数据) 发送给调度器
3)调度器从引擎接受网页(request数据),再转给下载器
然后获取页面的数据(response),发送给引擎,再提供给Spider分析。
4.存储内容下载器获得调度器的网页数据(request)。
Spider分析下载的response(用dmz.py中的分析方法parse)
并提取出item和需要跟进的url 的类(将网页的内容提取出我们需要的数据)
Scrapy Selectors(选择器):Select是一个选择器,有四个基本方法
1.xpath():传入xpath表达式,返回该表达式所对应的的所有节点的select list列表
xpath:一门在网页中查找特定信息的语言,用来筛选数据(比正则简单),解析html/xml对象。
2.css():传入css表达式,返回该表达式所对应的所有节点的selector list列表
3.extract():序列化该节点为unicode字符串并返回list
4.re():根据传入的正则表达式对数据进行提取。返回unicode字符串list列表
在Scrapy中不使用正则表达式,而是使用一种基于Xpath和CSS的表达式机制:Scrapy Selectors。
进入网址对应的Scrapy Shell
cmd项目窗口下:scrapy shell "http://www.dmoztools.net/Computers/Programming/Languages/Python/Books/"
进入后得到了reponse响应对象,可以尝试输出response.body或response.headers
尝试从其中获得 title、link、disc。用select选择器的四个方法来进行筛选
response.xpath(’//title’) :返回Selector对象的一个列表
字符串化: response.xpath(’//title’) .extract()
得到里面的文字:response.xpath(’//title/text()’)
shell里面会根据初始化的类型自动定义一个sel变量(可能等同于response)
快速获取xpath:审查元素,相应字段右键copy->copy xpath 复制粘贴
sites=sel.xpath('//ul/li')
for site in sites:
title = sites.path('a/text()').extract()
print(title)
将筛选后的数据存放到item里面去
最简单的工具是FixBox,他有四种形式方便导出
1)json
以json的方式导出到文件items.json
scrapy crawl dmoz -o items.json -t json
2)jsonlines
3)csv
4)xml
lxml
etree.HTML():把html的文本内容解析成html对象(会自动补全),同时也是XPath解析对象
html = etree.HTML(response.content.decode())#把html的文本内容解析成html对象
#etree读取文件进行解析
etree.tostring(html).decode(‘utf-8’):将html对象解析成字符串类型 并设置解码方式
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
'''
html = etree.HTML(text)
print(etree.tostring(html).decode('utf-8'))
xpath:对HTML文档进行搜索
html对象就是xpath解析对象
xpath常用规则(返回list)
/用于获取直接子节点,//用于获取子孙节点:
表达式 描述
nodename 选择这个节点名的所有子节点
/ 从当前节点选择直接子节点
// 从当前节点选取子孙节点
. 选择当前节点
… 选取当前节点的父节点
@ 选取属性
引入:from lxml import etree
例子:
/html/head/title:选取html文档中<head>标签内的<title>元素
/html/head/title/text():选择上面提到的<title>元素的文字
//td:选择所有的<td>元素
//div[@class="mine"]:选取所有具有class=“”mine“”属性的div元素
获取所有节点:
result = html.xpath('//*')
'//'表示获取当前节点子孙节点,'*'表示所有节点,'//*'表示获取当前节点下所有节点
for item in result:
print(item)
获取所有特定节点,如获取所有的li节点。
result = html.xpath('//li')#将*改为li,表示只获取名称为li的子孙节点
#返回一个列表
for item in result:
print(item)
获取所有某特定节点下的子节点(被父结点包围),如li结点下的a结点
result = html.xpath('//li/a')#//li选择所有的li节点,/a选择li节点下的直接子节点a
for item in result:
print(item)
根据属性获取特定节点:
result = html.xpath('//li[@class="item-3"]')
#返回class属性为item-3的li结点(列表形式)
获取特定属性
html.xpath('//ul[@id="pins"]/li/a/@href')
#获取id为pins的ul结点 下的子节点li 下的子节点 的href属性的值
异常处理
URLError:访问网页异常
import urllib.request as r
import urllib.error
req=r.Request("http://www/ooxx-fishc.com")
try:
r.urlopen(req)
except urllib.error.URLError as e:
print(e.reason)
HTTPError:状态码异常
http状态码大全
400-499:问题来自于客户端
500-599:服务器问题
except urllib.error.HPPTError as e:
print(e.reason)