热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python3大型网络爬虫实战004—scrapy大型静态商城网站爬虫项目编写及数据写入数据库实战—实战:爬取淘宝

原博文链接:http:www.aobosir.comblog20161226python3-large-web-crawler-taobao-com-import-to-MySQL

原博文链接:http://www.aobosir.com/blog/2016/12/26/python3-large-web-crawler-taobao-com-import-to-MySQL-database/


    • 开发环境
    • 开始实战
    • 设置防反爬机制settingspy 文件
    • 分析网站
  • 开始写爬虫程序taobaopy 文件
    • 创建一个爬虫文件taobaopy 文件
    • 添加需要使用的存储容器对象itemspy文件
    • 得到搜索关键字对应的所有搜索页面taobaopy文件
    • 得到所有商品的id
    • 得到所有商品的链接网址
  • 获取商品的具体信息taobaopy 文件
    • 获取商品的名字
    • 获取商品的链接网址taobaopy 文件
    • 获取商品的价格信息原价taobaopy 文件
    • 提取商品的累计评论数量使用抓包的方式taobaopy 文件
    • 构造具有评论数量信息的包的网址并获取商品的评论数量

开发环境

  • Python第三方库:lxml、Twisted、pywin32、scrapy
  • Python 版本:python-3.5.0-amd64
  • PyCharm软件版本:pycharm-professional-2016.1.4
  • 电脑系统:Windows 10 64位

如果你还没有搭建好开发环境,请到这篇博客。


  • 本文中的源代码在github这里:https://github.com/AoboJaing/thirdDemo/

本篇博文的重点内容:

  • 有一些数据,在源码上找不到的,这个时候需要使用 — 抓包。
  • Python调用MySQL数据库

本爬虫项目的目的是:某个关键字在淘宝上搜索到的所有商品,获取所有商品的: 商品名字、商品链接、商品价格、商品的评论。


开始实战

创建一个爬虫项目

scrapy startproject thirdDemo

Alt text

设置防反爬机制(settings.py 文件)

请参考这篇博客:给 Scrapy 爬虫项目设置为防反爬。

分析网站

  • 分析网页界面
  • 分析网址结构
  • 分析网页源代码

1 . 分析网页界面:

我们在淘宝网的搜索栏里面搜索关键字,比如“小吃”。它一共会输出100页。

可见:100页的搜索结果是淘宝的上限。(最多100页)

Alt text

2 . 分析网址结构:

当我们点击页面进行浏览时,我们发现不同的页面的网址有规律,并且下面是我们找到的规律:

  1. 红色部分是一模一样的。
  2. 删除红色部分,将剩下的组成网址,一样可以正常的浏览原网页。
  3. q= 后面是“小吃”的编码形式。
  4. s= 后面的数值等于 44*(当前页面-1)

Alt text

开始写爬虫程序(taobao.py 文件)

创建一个爬虫文件(taobao.py 文件)

cd thirdDemo
scrapy genspider -t basic taobao taobao.com

Alt text

使用PyCharm软件开发,使用PyCharm软件打开 thirdDemo项目。

Alt text

添加需要使用的存储容器对象(items.py文件)

先到 items.py 文件里面的ThirddemoItem()函数里面创建存储用到容器(类的实例化对象)

class ThirddemoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
link = scrapy.Field()
price = scrapy.Field()
comment = scrapy.Field()
pass

Alt text

得到搜索关键字对应的所有搜索页面(taobao.py文件)

在回调函数parse()中,建立一个变量(key)来存储关键词(零食)。然后在使用一个for循环来爬取所有的网页。然后使用scrapy.http里面的Request 来在parse()函数返回(返回一个生成器(yield))一个网页源代码:

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request

class TaobaoSpider(scrapy.Spider):
name = "taobao"
allowed_domains = ["taobao.com"]
start_urls = ['http://taobao.com/']

def parse(self, response):
key = '小吃'
for i in range(0, 2):
url = 'https://s.taobao.com/search?q=' + str(key) + '&s=' + str(44*i)
print(url)
yield Request(url=url, callback=self.page)
pass

def page(self, response):
pass

Alt text

(注意:我们上面通过观察网页已经知道了,搜索得到的页面有100页,但是我们现在是测试阶段,不爬这么多页,上面的代码我们只爬了2页)


运行一下:

Alt text

程序没有问题。


得到所有商品的id

我们现在的目标是得到搜索页面中所有商品的链接。

Alt text

现在,我们观察搜索页面的源代码,我们找这些商品链接的规律,能否通过什么商品id之类的信息,然后通过商品id来构造出商品的链接网址。

幸运的是:确实可以这么做。

我发现,不管是搜索的商品,不管是在淘宝里、天猫里、天猫超市里,商品的链接网址都可以用下面的格式去构造:

https://item.taobao.com/item.htm?id=商品的id

所以,现在我们要做的是:先提取商品的id:(使用正则表达式)

对搜索结果的网页随便一个地方右键:查看网页源代码(V)

(我发现:通过在浏览器中按F12 和 右键来 查看网页源代码 这两种查看源代码得到的源代码不一样,后者得到的源代码和爬虫爬取的源代码一致,而前者和爬虫爬取的不一致。)

所有我们不能使用Xpath表达式来用过标签获取商品id了。只能使用正则表达式了。

我想可能的原因是:搜索页面可能是动态构造出来的,所以使用Xpath表达式是不能对这种网址的源码进行提取信息的。(我瞎想的,不知道是否正确。不过事实其实是:使用Xpath表达式是提取不了有效信息的。)

Alt text

然后随便点击进入一个商品的链接网页,在这个网页的网址里面就可以找到这个商品的id:

Alt text

然后在刚刚打开的源代码中,查找这个id:

Alt text

我们通过观察发现,使用"nid":"就可以找到这个搜索结果页面里面所有商品的id:

Alt text

这个页面里面一共是36个商品,没错。

Q: 你可能发现了,这个搜索网页里面搜索到结果是48个商品,我们得到的是36个,是不是少了?

A: 没有少,这就是淘宝的营销策略。一个搜索页面一共有48个商品,但是其中有10多个商品是重复的!其中甚至有个商品在这个搜索页面中重复出现了三次,不信,你可以仔细的找找。

所以,商品的id可以使用下面的正则表达式获取:

'"nid":"(.*?)"'

我们在page()方法中得到爬取到的网页源代码的 body 标签里面的所有信息:

先声明一点:

爬取到的网页源代码是:以网页源代码中指定的编码方式编码得到的bytes信息。

Alt text

我们需要得到对应的解码信息:

参考网站:Python3 bytes.decode()方法

        body = response.body.decode('utf-8')

response.body 它默认是二进制格式,所以我们在使用它之前要给它解码:decode('utf-8'),为了避免出错,我给它传第二个参数:ignore

page()函数中的代码现在是下面这个样子的:

    def page(self, response):
body = response.body.decode('utf-8','ignore')
pattam_id = '"nid":"(.*?)"'
all_id = re.compile(pattam_id).findall(body)
print(all_id)
pass

运行试试看:

Alt text


得到所有商品的链接网址

现在得到了所有商品的ip,现在通过这些ip,构造出所有商品的网址。得到了链接后,就可以去爬这个网页的源代码了:(下面的代码中,在next()方法中将商品的网页网址打印了出来)

import re
    def page(self, response):
body = response.body.decode('utf-8','ignore')
pattam_id = '"nid":"(.*?)"'
all_id = re.compile(pattam_id).findall(body)
# print(all_id)
for i in range(0, len(all_id)):
this_id = all_id[i]
url = 'https://item.taobao.com/item.htm?id=' + str(this_id)
yield Request(url=url, callback=self.next)
pass
pass

def next(self, response):
print(response.url)
pass

运行试试看:(自动的将网址调整到正确的网址上。比如天猫或者天猫超市之类的子域名)

Alt text


获取商品的具体信息(taobao.py 文件)

获取商品的名字

现在在next()回调函数中实例化一个开始时在items.py文件里面创建的项目的存储容器对象。然后,我们就可以直接使用它了。

所以现在在 taobao.py 文件的上面添加这个文件:

from thirdDemo.items import ThirddemoItem

现在我们要得到商品的标题。

我们尽量从源代码中的信息提取,如果源代码中没有的信息,我们在使用抓包的凡是提取。

标题是可以直接在源代码中提取的:(观察网页源代码,直接中Xpath表达式)

天猫或者天猫超市的商品的标题可以使用下面的Xpath表达式提取:

title = response.xpath("//div[@class='tb-detail-hd']/h1/text()").extract()

淘宝的商品的标题可以使用下面的Xpath表达式提取:

title = response.xpath("//h3[@class='tb-main-title']/@data-title").extract()

所以,这里提取标题,我们需要一个判断语句,判断这个商品的网址链接是天猫的还是淘宝的。

伪码如下:

if 不是淘宝的网址:
title = response.xpath("//div[@class='tb-detail-hd']/h1/text()").extract() # 天猫或者天猫超市
else:
title = response.xpath("//h3[@class='tb-main-title']/@data-title").extract() # 淘宝

我们的判断标准就是商品网址的子域名。子域名大致一共有三种:detail.tmall(天猫)、chaoshi.detail.tmall(天猫超市)、item.taobao(淘宝)

    def next(self, response):
# print(response.url)
url = response.url
pattam_url = 'https://(.*?).com'
subdomain = re.compile(pattam_url).findall(url)
# print(subdomain)
if subdomain[0] != 'item.taobao':
title = response.xpath("//div[@class='tb-detail-hd']/h1/text()").extract()
pass
else:
title = response.xpath("//h3[@class='tb-main-title']/@data-title").extract()
pass
self.num = self.num + 1;
print(title)
pass

运行试试看:

Alt text

有的时候,偶尔会得到几个 [],这是因为,你爬的太快的,淘宝的服务器没有同意你爬取这个商品的网页。(所以提高防反爬机制,效果会好一些。)

Alt text

获取商品的链接网址(taobao.py 文件)

(直接得到)

        item['link'] = response.url

获取商品的价格信息(原价)(taobao.py 文件)

正常的价格可以在商品网页的源代码里面获取,但是淘宝价(促销价)在商品源代码里面没有,这时就需要通过抓包来获取。

淘宝:

Alt text

天猫:

Alt text

我们先获取正常的价格。这里也需要分淘宝和天猫,它们获取正常价格的Xpath表达式或者正则表达式不同。

注意:这里总结表达式,通过对商品页面右键 -> 查看网页源代码 的方式查看源代码。

        if subdomain[0] != 'item.taobao':
pattam_price = '"defaultItemPrice":"(.*?)"'
price = re.compile(pattam_price).findall(response.body.decode('utf-8', 'ignore')) # 天猫
pass
else:
price = response.xpath("//em[@class = 'tb-rmb-num']/text()").extract() # 淘宝
pass
print(price)

提取商品的累计评论数量:(使用抓包的方式)(taobao.py 文件)

淘宝:

Alt text

天猫:

Alt text

可以使用 : Fiddler4抓包软件 或者 浏览器按F12->Network->Name->Response查看抓包信息

这里,我通过浏览器进行抓包,找到了评论数所在的包:(一个一个的找)

淘宝:

Alt text

观察这个包的网址:

Alt text

这个网址,我们可以在浏览器中复制,再访问以下:(是可以正常访问的)

Alt text

https://rate.taobao.com/detailCommon.htm?auctiOnNumId=533237707421&userNumId=1990097437&ua=097UW5TcyMNYQwiAiwQRHhBfEF8QXtHcklnMWc%3D%7CUm5Ockt%2BQ3dDfkB8R35Eey0%3D%7CU2xMHDJ7G2AHYg8hAS8XKQcnCVU0Uj5ZJ11zJXM%3D%7CVGhXd1llXGlUYFRpV2tQaVFvWGVHekV8RHtBf0Z%2FQXRKdUx1T3VOYDY%3D%7CVWldfS0TMw8xBD8fIAAubQslcyU%3D%7CVmJCbEIU%7CV2lJGSQEORklGCMYOAI%2FADkZJREuEzMPMgc6GiYSLRAwDDEJNGI0%7CWGFcYUF8XGNDf0Z6WmRcZkZ8R2dZDw%3D%3D&callback=json_tbc_rate_summary

我发现上面的这个网址可以缩减为:

https://rate.taobao.com/detailCommon.htm?auctiOnNumId=533237707421
https://rate.taobao.com/detailCount.do?_ksTS=1480993623725_99&callback=jsonp100&itemId=533237707421

而这个533237707421就是商品的id。好了,找到这个网址的规律,现在可以> 手动构造这个评论数的网址了:

天猫:

Alt text

https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=35338957824&spuId=235704813&sellerId=628189716&_ksTS=1480992656788_203&callback=jsonp204

可以缩减为:

https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=35338957824

最后,我们发现:不管是淘宝还是天猫,都可以使用下面这个构造方式来得到含有正确评论数量的网址:

https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=商品id

注意:使用https://rate.taobao.com/detailCommon.htm?auctiOnNumId=商品id 这种网址也可以,但是在对天猫商品得到评价数量和网页里面显示的不同。所以我们不使用这个构造方法。

Alt text

Alt text

所以通过商品id就可以得到含有评论数量信息的包的网址。现在在next()方法中需要通过商品的URL获取商品的id。

Alt text

我们从上面的图中看到:天猫和淘宝的网址不同,所以,从网址中获取商品id的正则表达式也就不同。下面的代码的功能就是从商品的url中提取商品id:

        # 获取商品的id(用于构造商品评论数量的抓包网址)
if subdomain[0] != 'item.taobao': # 如果不属于淘宝子域名,执行if语句里面的代码
pattam_id = 'id=(.*?)&'
this_id = re.compile(pattam_id).findall(url)[0]
pass
else:
# 这种情况是不能使用正则表达式的,正则表达式不能获取字符串最末端的字符串
pattam_id = 'id=(.*?)$'
this_id = re.compile(pattam_id).findall(url)[0]
pass
print(this_id)

注意:$ : 在正则表达式里面的作用是:匹配字符串末尾。

举例:当url = 'https://item.taobao.com/item.htm?id=535023141744' 时,这是一个淘宝网站里面的一个商品,现在我们想得到这个网址里面的商品id。

如果你把正则表达式写成这个样子:pattam_id = 'id=(.*?)',是匹配不到结果的(商品id)。

正则表达式是通过字符串上下文来匹配你需要的信息的,如果只有“上文”,没有“下文”时,对于使用正则表达式匹配字符串末端字符串,需要在正则表达式中使用$


运行试试看,一切都在掌控之中。

构造具有评论数量信息的包的网址,并获取商品的评论数量

得到目标抓包网址,获取它的源代码,然后提取评论数量:

import urllib
        # 构造具有评论数量信息的包的网址
comment_url = 'https://dsr-rate.tmall.com/list_dsr_info.htm?itemId=' + str(this_id)

# 这个获取网址源代码的代码永远也不会出现错误,因为这个URL的问题,就算URL是错误的,也可以获取到对应错误网址的源代码。
# 所以不需要使用 try 和 except urllib.URLError as e 来包装。
comment_data = urllib.request.urlopen(comment_url).read().decode('utf-8', 'ignore')
pattam_comment = '"rateTotal":(.*?),"'
comment = re.compile(pattam_comment).findall(comment_data)
# print(comment)
item['comment'] = comment

现在返回item对象:

        yield item

Alt text


现在,我们就可以在pipline.py文件里面来对我们得到的这些商品数据进行一些操作了,比如打印到终端或者保存到数据库中。

但在这之前,我们需要设置一下settings.py文件,将下面的代码的注释去掉:

Alt text


pipline.py文件中对taobao.py爬虫文件返回的item对象进行处理(比如打印到终端,或者保存到数据库中)

将得到的信息打印到终端中:

class ThirddemoPipeline(object):
def process_item(self, item, spider):
title = item['title'][0]
link = item['link']
price = item['price'][0]
comment = item['comment'][0]
print('商品名字', title)
print('商品链接', link)
print('商品正常价格', price)
print('商品评论数量', comment)
print('------------------------------\n')
return item

运行试试看:

Alt text


下面是将得到的信息保存到数据库中的操作:

第一件事情就是 启动数据库,启动数据库的代码一般我们是将它写到默认的__init__(self)函数中,这个方法就是最开始做的事情。

要想连接到数据库,首先要有数据库:使用MySQL数据库

在python上要想使用MySqL数据库,需要先安装pymysql库这个模块。

Alt text

有打开数据库的函数,就要有关闭数据库的方法。

Alt text

现在,我们在process()函数中处理数据,将数据插入到数据库里面。并且加一个异常处理,因为我不希望程序运行的时候会出现错误而终止,并且我也不想

Alt text


请访问:http://www.aobosir.com/


推荐阅读
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了关于apache、phpmyadmin、mysql、php、emacs、path等知识点,以及如何搭建php环境。文章提供了详细的安装步骤和所需软件列表,希望能帮助读者解决与LAMP相关的技术问题。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
author-avatar
QX封面精选
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有