淘宝增加爬虫并分析

This commit is contained in:
criseLYJ
2019-03-07 02:20:33 +08:00
parent a55bbaf32d
commit c137e8a843
12 changed files with 686 additions and 3 deletions
+13 -3
View File
@@ -56,21 +56,31 @@
## show
- bilibili自动登录测试正常,成功率98%
### bilibili自动登录测试正常,成功率98%
![](./image/bilibili.jpg)
- web微信
### web微信
![Alt text](./image/weixin.jpg)
- 图虫爬虫
### 图虫爬虫
![](./image/Jietu20190306-232224.jpg)
![](./image/Jietu20190306-232303.jpg)
### 淘宝 - 淘宝网
- taobao.py 为模拟登录
- 剩下的为爬虫
```
1. 爬取淘宝各子标签,按销量排名商品信息,按分类保存至MongoDB
2. 通过pandas进行数据分析
3. 将商品在各省分布、销量排行、地图分布等通过matplotlib绘图显示
```
## tips of pull request
- 欢迎大家一起来 pull request
BIN
View File
Binary file not shown.
+11
View File
@@ -0,0 +1,11 @@
# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.io/en/latest/deploy.html
[settings]
default = taobao.settings
[deploy]
#url = http://localhost:6800/
project = taobao
View File
+21
View File
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class TaobaoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
goods_url=scrapy.Field()
title=scrapy.Field()
price=scrapy.Field()
sell_count =scrapy.Field()
goods_class=scrapy.Field()
seller=scrapy.Field()
area=scrapy.Field()
+103
View File
@@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
# Define here the models for your spider middleware
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
from scrapy import signals
class TaobaoSpiderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the spider middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_spider_input(self, response, spider):
# Called for each response that goes through the spider
# middleware and into the spider.
# Should return None or raise an exception.
return None
def process_spider_output(self, response, result, spider):
# Called with the results returned from the Spider, after
# it has processed the response.
# Must return an iterable of Request, dict or Item objects.
for i in result:
yield i
def process_spider_exception(self, response, exception, spider):
# Called when a spider or process_spider_input() method
# (from other spider middleware) raises an exception.
# Should return either None or an iterable of Response, dict
# or Item objects.
pass
def process_start_requests(self, start_requests, spider):
# Called with the start requests of the spider, and works
# similarly to the process_spider_output() method, except
# that it doesnt have a response associated.
# Must return only requests (not items).
for r in start_requests:
yield r
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
class TaobaoDownloaderMiddleware(object):
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader middleware does not modify the
# passed objects.
@classmethod
def from_crawler(cls, crawler):
# This method is used by Scrapy to create your spiders.
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
return s
def process_request(self, request, spider):
# Called for each request that goes through the downloader
# middleware.
# Must either:
# - return None: continue processing this request
# - or return a Response object
# - or return a Request object
# - or raise IgnoreRequest: process_exception() methods of
# installed downloader middleware will be called
return None
def process_response(self, request, response, spider):
# Called with the response returned from the downloader.
# Must either;
# - return a Response object
# - return a Request object
# - or raise IgnoreRequest
return response
def process_exception(self, request, exception, spider):
# Called when a download handler or a process_request()
# (from other downloader middleware) raises an exception.
# Must either:
# - return None: continue processing this exception
# - return a Response object: stops process_exception() chain
# - return a Request object: stops process_exception() chain
pass
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
+32
View File
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import pymongo
class TaobaoPipeline(object):
def __init__(self,mongo_url,mongo_db):
self.mongo_url=mongo_url
self.mongo_db=mongo_db
@classmethod
def from_crawler(cls,crawler):
return cls(
mongo_url=crawler.settings.get("MONGO_URL"),
mongo_db=crawler.settings.get("MONGO_DB")
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_url)
self.db = self.client[self.mongo_db]
def process_item(self, item, spider):
sheet = self.db[item['goods_class']]
if sheet.find_one({'goods_url':item['goods_url']}):
print('数据已存在')
else:
sheet.insert(dict(item))
return item
+106
View File
@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
# Scrapy settings for taobao project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
# https://doc.scrapy.org/en/latest/topics/settings.html
# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html
BOT_NAME = 'taobao'
SPIDER_MODULES = ['taobao.spiders']
NEWSPIDER_MODULE = 'taobao.spiders'
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'taobao (+http://www.yourdomain.com)'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
# Disable cookies (enabled by default)
COOKIES_ENABLED = False
# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False
# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
#}
# Enable or disable spider middlewares
# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html
SPIDER_MIDDLEWARES = {
# 'taobao.middlewares.TaobaoSpiderMiddleware': 543,
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
# 'taobao.middlewares.TaobaoDownloaderMiddleware': 543,
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
# Enable or disable extensions
# See https://doc.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
# 'scrapy.extensions.telnet.TelnetConsole': None,
#}
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'taobao.pipelines.TaobaoPipeline': 300,
}
# Enable and configure the AutoThrottle extension (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False
# Enable and configure HTTP caching (disabled by default)
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = 'httpcache'
#HTTPCACHE_IGNORE_HTTP_CODES = []
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
# REDIRECT_ENABLED = False
SPLASH_URL='http://localhost:8050'
# REDIS_URL='redis://:zkyr1006@localhost:6379/1'
MONGO_URL = 'mongodb://admin:zkyr1006@localhost:28018'
MONGO_DB='taobao'
# 遇到502504,重复请求
RETRY_HTTP_CODES = [502, 504]
+4
View File
@@ -0,0 +1,4 @@
# This package will contain the spiders of your Scrapy project
#
# Please refer to the documentation for information on how to create and manage
# your spiders.
+216
View File
@@ -0,0 +1,216 @@
#!/home/zkfr/.local/share/virtualenvs/xf-5EfV3Nly/bin/python
#-*- coding:utf-8 -*-
# @author : MaLei
# @datetime : 2018-10-06 12:50
# @file : analysis.py
# @software : PyCharm
import numpy as np
from pymongo import MongoClient
from matplotlib import pyplot as plt
import re,json,jieba,pandas
from collections import Counter
from wordcloud import WordCloud
import seaborn as sns
# matprotlib显示中文
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 从mongodb中获取数据
def data_analysis(parameter):
client = MongoClient('mongodb://admin:zkyr1006@localhost:28018')
db = client.taobao
colls = [db.内搭, db.外套, db.牛仔裤, db.秋季套装]
data=[]
for coll in colls:
list_data=coll.aggregate([{'$group': {'_id': 0, parameter: {'$push': '$'+parameter}}}]).next()[parameter]
data+=list_data
return data
# print(provience)
# 商品所属省份分布柱状图
def provience():
data=[]
provs=data_analysis('area')
# print(provience)
for each in provs:
prov = (each.split())[0]
data.append(prov)
count={}
for i in data:
count[i]=data.count(i)
# print(count)
prov=list(count.keys())
nums=list(count.values())
return prov,nums
def prov_plt():
prov, nums = provience()
plt.figure(figsize=(8, 4))
plt.xticks(rotation=0)
plt.bar(prov, nums, color='g')
plt.xlabel('省份')
plt.ylabel('数量')
plt.title('不同省份数量分布图')
plt.legend()
plt.show()
# 词云及根据词云数据进行分析的柱状图
def cloud_plt():
def cloud_data():
title=data_analysis('title')
titles=[]
# 对每个标题进行分词
for each in title:
title_cut=jieba.lcut(each)
titles.append(title_cut)
# 剔除不需要的词语
title_del=[]
for line in titles:
line_del=[]
for word in line:
if word not in ['2018','妈妈','','','',' ','Chinism','工作室','倔强']:
line_del.append(word)
title_del.append(line_del)
# print(title_del)
# 元素去重,每个标题中不含重复元素
title_clean=[]
for each in title_del:
line_dist=[]
for word in each:
if word not in line_dist:
line_dist.append(word)
title_clean.append(line_dist)
# 将所有词语转为一个list
allwords_dist=[]
for line in title_clean:
for word in line:
allwords_dist.append(word)
# 把列表转为数据框
allwords_dist=pandas.DataFrame({'allwords':allwords_dist})
# 对词语进行分类汇总
word_count=allwords_dist.allwords.value_counts().reset_index()
# 添加列名
word_count.columns=['word','count']
# print(allwords_dist)
return word_count,title_clean
def cloud_data_count():
# 获取商品销量数据
sell_count = data_analysis('sell_count')
word_count, title_clean = cloud_data()
ws_count = []
# 商品中包含统计的词时,将其销量加入list
for each in word_count.word:
i = 0
s_list = []
for t in title_clean:
if each in t:
s_list.append(int(sell_count[i]))
# print(s_list)
i += 1
# 统计一个关键词所包含商品的销量总数
ws_count.append(sum(s_list))
# 把列表转为数据框
ws_count = pandas.DataFrame({'ws_count': ws_count})
# 把word_count, ws_count合并为一个表
word_count = pandas.concat([word_count, ws_count], axis=1, ignore_index=True)
word_count.columns = ['word', 'count', 'ws_count']
# 升序排列
word_count.sort_values('ws_count', inplace=True, ascending=True)
# 取最大30行数据
df_ws = word_count.tail(30)
return df_ws
# 图云部分
word_count=cloud_data()[0]
# 设置字体,背景颜色,字体最大号,
w_c=WordCloud(font_path='/usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf/simhei.ttf',
background_color='white',
max_font_size=60,
margin=1)
# 取前400个词进行可视化
wc=w_c.fit_words({x[0]:x[1] for x in word_count.head(1000).values})
# 设置图优化
plt.imshow(wc,interpolation='bilinear')
# 去除边框
plt.axis('off')
plt.show()
# 统计分析柱状图部分
data = cloud_data_count()
index = np.arange(data.word.size)
# plt.figure(figsize=(6,12))
plt.barh(index, data.ws_count, align='center', alpha=0.8)
plt.yticks(index, data.word)
# 添加数据标签
for y, x in zip(index, data.ws_count):
plt.text(x, y, '%.0f' % x, ha='left', va='center')
plt.show()
def impact_analysis():
sell_count=pandas.DataFrame({'sell_count': data_analysis('sell_count')})
price=[]
for i in data_analysis('price'):
p=i.split('-')
p_i=p[0].split('.')
price.append(p_i[0])
price=pandas.DataFrame({'price':price})
infos=pandas.concat([sell_count, price], axis=1, ignore_index=True)
infos.columns = ['sell_count', 'price'] #一定注意定义到columns
infos['sell_count']=infos.sell_count.astype('int')
infos['price']=infos.sell_count.astype('int')
infos['GMV']=infos['sell_count']*infos['price']
# print(infos.GMV.dtype)
sns.regplot(x='price',y='GMV',data=infos)
# sns.lmplot(x='price',y='GMV',data=infos,x_jitter=.05)
plt.show()
def mean_sale():
prov,nums=provience()
sell_count = data_analysis('sell_count')
areas=[]
count=[]
for i in data_analysis('area'):
areas.append((i.split(' '))[0])
for each in prov:
counts=[]
for i in range(0,len(areas)):
if each==areas[i]:
counts.append(int(sell_count[i]))
count.append(sum(counts))
# print(count)
count=pandas.DataFrame({'count':count})
prov=pandas.DataFrame({'prov':prov})
nums=pandas.DataFrame({'nums':nums})
data = pandas.concat([nums,count], axis=1, ignore_index=True)
data.columns = ['nums','count']
data['nums']=data.nums.astype('int')
m_l=data['count']/data['nums']
mean_list=[]
for each in m_l:
each=str(each).split('.')
mean_list.append(each[0])
mean_list=pandas.DataFrame({'mean_list':mean_list},dtype=np.int)
infos = pandas.concat([prov,mean_list], axis=1, ignore_index=True)
infos.columns = ['prov','mean_list']
infos['mean_list']=infos.mean_list.astype('int')
infos.sort_values('mean_list',inplace=True,ascending=False)
infos=infos.reset_index()
index=np.arange(infos.mean_list.size)
print(infos)
plt.figure(figsize=(8,4))
plt.bar(index,infos.mean_list,color='purple')
plt.xticks(index,infos.prov,rotation=0)
plt.xlabel('省份')
plt.ylabel('平均销量')
plt.title('不同省份销量分布')
plt.show()
mean_sale()
# def hot_map():
+132
View File
@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
import scrapy,numpy
from scrapy import Selector
from taobao.items import TaobaoItem
from scrapy.spiders import CrawlSpider, Rule
from bs4 import BeautifulSoup
import requests,re
from scrapy_splash import SplashRequest
from urllib.parse import urlencode
class comicspider(scrapy.Spider):
name = 'tb'
allowed_domains=['www.taobao.com']
start_urls=['https://www.taobao.com']
headers1 = {
'Connection': 'keep-alive',
'Host': 'www.taobao.com',
'Accept-Encoding':'gzip, deflate, br',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'
}
def start_requests(self):
yield scrapy.Request(url=self.start_urls[0],callback=self.sub_nav,headers=self.headers1)
def sub_nav(self, response):
page=Selector(response)
# 女装、男装、内衣
# sub_navs1=page.xpath('//ul[@class="service-bd"]/li[position()<2]/a/text()').extract()
# print(sub_navs1)
sub_urls1=page.xpath('//ul[@class="service-bd"]/li[position()<2]/a/@href').extract()
# print(sub_urls1)
for sub_url in sub_urls1:
yield scrapy.Request(url=sub_url,callback=self.parse0,headers=self.headers1,dont_filter=True)
def parse0(self, response):
headers2 = {
'Connection': 'keep-alive',
'Host': 's.taobao.com',
'Accept-Encoding': 'gzip, deflate, br',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'
}
page=Selector(response)
# 连衣裙、毛衫/内搭、秋外套……
sub_navs11=page.xpath('//dl[@class="theme-bd-level2"]/dt/div/a/text()').extract()
del sub_navs11[-1]
sub_urls11=page.xpath('//dl[@class="theme-bd-level2"]/dt/div/a/@href').extract()
del sub_urls11[-1]
for i in range(0,len(sub_urls11)):
page_urls=[]
page_urls.append(sub_urls11[i]+'&sort=sale-desc')
s=0
sub_nav=sub_navs11[i]
for j in range(1,20):
# for j in range(0, 1):
senddata = {
'sort':'sale-desc',
'bcoffset': '0',
's': s
}
page_url=sub_urls11[i]+'&'+ urlencode(senddata)
page_urls.append(page_url)
s+=60
# print(page_urls)
for page_url in page_urls:
yield SplashRequest(page_url,self.parse1,args={'wait':0.5},splash_headers=headers2,dont_filter=True,meta={'sub_nav':sub_nav})
# yield scrapy.Request(page_url,callback=self.parse1,headers=headers2,dont_filter=True,meta={'sub_nav':sub_nav})
def parse1(self, response):
headers3 = {
'Connection': 'keep-alive',
'Host': 'item.taobao.com',
'Accept-Encoding': 'gzip, deflate, br',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'
}
page=Selector(response)
goods_urls=page.xpath('//div[@class="grid g-clearfix"]/div[@class="items"]/div/div[3]/div[2]/a/@href').extract()
# goods_class=page.xpath('//div[@class="grid g-clearfix"]/div[@class="items"]/div[1]/div[3]/div[2]/a/span[@class="H"]/text()').extract()
goods_class=response.meta['sub_nav']
areas = page.xpath('//div[@class="row row-3 g-clearfix"]/div[@class="location"]/text()').extract()
sell_counts=page.xpath('//div[@class="deal-cnt"]/text()').extract()
# print(goods_urls)
for i in range(0,len(goods_urls)):
area=areas[i]
sell_count=sell_counts[i]
goods_url='http:'+goods_urls[i]
yield scrapy.Request(goods_url,self.parse2,headers=headers3,dont_filter=True,
meta={'goods_url':goods_url,
'goods_class':goods_class,
'area':area,
'sell_count':sell_count})
def parse2(self, response):
item=TaobaoItem()
page=Selector(response)
# print(response.text)
item['title']=page.xpath('//head/title/text()').extract()[0][:-4]
item['goods_url']=response.meta['goods_url']
item['goods_class']=response.meta['goods_class']
item['price']=page.xpath('//strong[@id="J_StrPrice"]/em[@class="tb-rmb-num"]/text()').extract()[0]
item['sell_count']=response.meta['sell_count'][:-3]
item['area']=response.meta['area']
# item['trade']=page.xpath('//div[@class="tb-sell-counter"]/a/strong/text()').extract()
seller= page.xpath('//div[@class="tb-shop-name"]/dl/dd/strong/a/@title').extract()
if len(seller)==1:
item['seller']=seller[0]
else:
seller=page.xpath('//span[@class="shop-name-title"]/@title').extract()
if len(seller)==1:
item['seller'] = seller[0]
else:
seller = page.xpath('//span[@class="shop-name-title"]/@title').extract()
if len(seller) == 1:
item['seller'] = seller[0]
else:
item['seller'] = '未知'
yield item
+48
View File
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
import requests
# headers = {
# 'Connection': 'keep-alive',
# 'Host': 'item.taobao.com',
# 'Accept-Encoding': 'gzip, deflate, br',
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'
# }
# url='https://item.taobao.com/item.htm?spm=a219r.lm874.14.1.422f2140YG82hc&id=574990577169&ns=1&abbucket=20#detail'
# # yield SplashRequest(page_url, self.parse1, args={'wait': 0.5}, splash_headers=self.headers, dont_filter=True)
# page=requests.get(url,headers=headers)
# print(page.text)
import re
# Start your middleware class
class ProxyMiddleware(object):
# overwrite process request
def process_request(self, request, spider):
# Set the location of the proxy
request.meta['proxy'] =self.proxy_test()
def proxy_test(self):
# ....
def get_proxy():
return requests.get("http://192.168.1.137:8001/get/").text
def delete_proxy(proxy):
requests.get("http://192.168.1.137:8001/delete/?proxy={}".format(proxy))
proxy = "http://{}".format(get_proxy())
try:
requests.get('https://www.baidu.com', proxies={"proxy": proxy})
print(proxy,'代理可用')
# 使用代理访问
return proxy
except Exception:
# 出错1次, 删除代理池中代理
delete_proxy(proxy)
return None
DOWNLOADER_MIDDLEWARES = {
# 'taobao.middlewares.TaobaoDownloaderMiddleware': 543,
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
'taobao.middlewares.ProxyMiddleware': 100,
}