You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wkyuu 372b3db354
修改了线程逻辑,用线程池加快了整个流程
3 years ago
README.md 修改了线程逻辑,用线程池加快了整个流程 3 years ago
downloader.py 完善历史价格查询 3 years ago
historyPrice.py 修改了线程逻辑,用线程池加快了整个流程 3 years ago
middlewares.py 修改了线程逻辑,用线程池加快了整个流程 3 years ago
milkSpider.py update via git 3 years ago
pipelines.py 修改了线程逻辑,用线程池加快了整个流程 3 years ago
settings.py 历史价格 3 years ago

README.md

milkSpider

selenium + redis + 分布式 + xpath + etree + 可视化

任务爬取京东网站上在售的各类牛奶品类的商品名称简介价格相关评论区相关。并给出相应的价格波动趋势精选好评用python的可视化展示。计划任务自动爬取。

TODO

  • 初始化 selenium 框架,编写好相应的爬取规则,初步实现小规模爬取内容
  • 从历史价格网页爬取历史价格
    • 同时/后期追加 存入csv 价格趋势,涨跌幅。比对,给出价格波动趋势
  • 加入Redis分布式设计
  • 数据可视化
    • 预计两种模式终端交互随机或取评价数为索引目标给出取出的item的具体信息例如价格预测。
      • 选择目录,友好的选择交互体验
      • 选择抽取item模式热评就列出前五条随机就随机取一条
  • python打包exe需要图形化界面

project

项目目录

Selesium

downloader.py 下载器,即爬取内容

middlewares.py 配置分布式线程redis相关内容

pipelines.py 处理得到的数据,存储到相应文件

milkSpider.py 主文件,配置爬取设置,自动化等

historyPrice.py 爬取历史价格

selenium

配置下载器利用selenium模拟浏览器正常浏览行为

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from lxml import etree

def getsource(url):
    init = Options()

    init.add_argument('--no-sandbox')
    init.add_argument('--headless')
    init.add_argument('--disable-gpu')
    init.add_argument("disable-cache")
    init.add_argument('disable-infobars')
    init.add_argument('log-level=3')    # INFO = 0 WARNING = 1 LOG_ERROR = 2 LOG_FATAL = 3 default is 0
    init.add_experimental_option("excludeSwitches",['enable-automation','enable-logging'])

    driver = webdriver.Chrome(chrome_options = init)
    driver.implicitly_wait(10)
    driver.get(url)

    response = etree.HTML(driver.page_source)
    response = etree.tostring(response, encoding = "utf-8", pretty_print = True, method = "html")
    response = response.decode('utf-8')

    driver.close()
    return response

安装,初始化

GIT

# 安装git
winget install --id Git.Git -e --source winget
## 或者官网下载
https://git-scm.com/download/win
# 在powershell中使用
vim $PROFILE
## 修改相应的位置为 GITPATH = ~/Git/cmd/git.exe
## SetAlias git $GITPATH

git init
git remote add origin https://bdgit.educoder.net/mf942lkca/milkSpider.git
git pull https://bdgit.educoder.net/mf942lkca/milkSpider.git
git remote -v	# 查看远程仓库信息
touch .gitignore	# 创建忽略上传控制文件

git add *.py	# 添加要push的本地内容到一个本地临时仓库
git commit -m "update"	# 先添加一个commit
git push -u origin master	# push, 出错就 -f(注意会造成不可回避的损失)

selenium

安装

# 安装selenium
pip3 install selenium

# 查看配置信息
pip how selenium

调用时导入的内容

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
# chrome_options.add_argument('lang=zh_CN.UTF-8')	# 设置中文
chrome_options.add_argument('--headless')  # 无界面
chrome_options.add_argument('--no-sandbox')  # 解决DevToolsActivePort文件不存在报错问题
chrome_options.add_argument('--disable-gpu')   # 禁用GPU硬件加速。如果软件渲染器没有就位则GPU进程将不会启动。
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--window-size=1920,1080')  # 设置当前窗口的宽度和高度
driver = webdriver.Chrome('chromedriver',chrome_options=chrome_options)
#driver = webdriver.Chrome()
url = ""
driver.get(url)
print(driver.page_source)
driver.quit()

一些备忘录

text = """this is test content;这是测试内容。"""
html1 = etree.HTML(text)
# html1 = etree.fromstring(text) # 同HTML()

# 方法1 使用html.unescape()
res = etree.tostring(html1)
print(html.unescape(res.decode('utf-8')))

# 方法2 使用uft-8编码
res = etree.tostring(html1,encoding="utf-8") # 这种方法对标签用的中文属性无效
print(res.decode('utf-8'))

# 方法1 使用open读取文档做字符串处理
with open('test.html') as f:
    html1 = etree.HTML(f.read())
# 之后代码同 处理字符串 的两种方法

# 方法2 parse读取文档时指定编码方式
html1 = etree.parse('test.html',etree.HTMLParser(encoding='utf-8'))
# 这里要指定正确(与所读取文档相应的编码)的编码方式,不然后面会出现乱码
# 之后代码同 处理字符串 的两种方法

请求头cookie等

# 访问 https://httpbin.org/get?show_env=1 可以返回当前浏览器的请求信息
options.add_argument('lang=zh_CN.UTF-8')

# 贴一个用json模块保存cookies
def getCookies():
    with open('cookies.json', 'r', encoding='utf-8') as fd:
            listCookies = json.loads(fd.read())
    for cookie in listCookies:
        cookies = {
            'domain': cookie['domain'],
            'httpOnly': cookie['httpOnly'],
            'name':cookie['name'],
            'path':'/',
            'secure': cookie['secure'],
            'value':cookie['value'],
        }
        print(cookies)

def saveCookies(driver):
    jsonCookies = json.dumps(driver.get_cookies())
    with open('cookies.json', 'w', encoding='utf-8') as fd:
        fd.write(jsonCookies)

ChromeDriver

下载 ChromeDriver 放到当前目录就行(如果是放在 python 根目录可以不用在实例化 selenium 时指定chromedriver 路径)

Matplotlib

Requests

经典老碟

import requests

线程

多线程,手动版

import threading
import time

threadlines = 16    # 默认调用16个线程不要超过20
flag = 1    # 判断主线程

def printTime(name):
    print("name", time.ctime())
    delay(4)
	print("name", time.ctime())
    
threads = []
for thread in range(threadlines):
    name = "thread " + str(thread)
    athread = printTime(name)
    athread.start()
    threads.append(athread)

for thread in threads:	# 加入阻塞,在子线程没完全结束前,保证主线程不断
    thread.join()

线程锁

import threading
import time

threadLock = threading.Lock()
threadlines = 16    # 默认调用16个线程不要超过20
flag = 1    # 判断主线程

def printTime(name):
    print("name", time.ctime())
    delay(4)
	print("newname", time.ctime())
    newtime = str(time.ctime())
    threadLock.acquire()	# 获得对txt文件的锁独享操作权限
    write2txt(newname)
    threadLock.release()	# 释放锁(把独享权限让出)

def write2txt(name):
    with open('test.txt', 'a+', encoding = 'utf-8') as fd:
        fd.write(name)
    
threads = []
for thread in range(4):
    name = "thread " + str(thread)
    athread = printTime(name)
    athread.start()
    threads.append(athread)

for thread in threads:	# 加入阻塞,在子线程没完全结束前,保证主线程不断
    thread.join()

线程池,建议用

from concurrent.futures import ThreadPoolExecutor
import time

def printTime(name):
    print("name", time.ctime())
    delay(4)
	print("newname", time.ctime())
    
with ThreadPoolExecutor(max_workers = 10) as thread:
    for count in range(10):
        name = "thread" + str(count)
        task = thread.submit(printTime, (name))	# 传入函数和对应需要的参数
        print(task.done())	# 查看该线程是否完成bool
        print(task.result())	# 返回上面 printTime 函数的返回值

Redis

# 安装 redis 模块
## pip install redis

# 实例对象
redisconn = redis.Redis(host = '127.0.0.1', port = '6379', password = 'x', db = 0)

# redis 取出的结果默认是字节,我们可以设定 decode_responses=True 改成字符串

备注

  • 没有历史查询

在没有使用线程之前,完整跑完五个种类共(30 x 10 x 5 = 1500)条数据用时365s

使用线程数为5的情况下完整跑完五个种类共 1500条数据用时130s

使用线程数为16的情况下完整跑完五个种类共 1500条数据用时80s

  • 加了历史查询

在不使用线程池的情况下,完整跑完 1500条数据用时很久

在使用线程池的情况下,完整跑完 1500条数据用时544秒

参考链接

1selenium+python自动化100-centos上搭建selenium启动chrome浏览器headless无界面模式

2解决:'chromedriver' executable needs to be in PATH问题

3Python selenium-chrome禁用打印日志输出

4Python将list逐行读入到csv文件中

5Git中使用.gitignore忽略文件的推送

6python 3 实现定义跨模块的全局变量和使用

7Python 多线程

8Python redis 使用介绍

9python + redis 实现 分布式队列任务

10深入理解Python线程中join()函数

11如何理解Python装饰器- 知乎

12【自动化】selenium设置请求头

13python selenium 保存cookie 读取cookie

14Selenium添加Cookie的方法

15requests库使用方法汇总笔记

16爬虫常见的HTTP错误代码及错误原因

17Python字符串操作之字符串分割与组合

18python线程池

19