本文最后更新于 2023-10-12,文章内容可能已经过时。

爬虫

立项作品,使用爬虫爬取电商网站的信息,并进行数据分析和展示.

1.京东:

import requests
from bs4 import BeautifulSoup
import xlwt
​
def get_html(url):
    # 模拟浏览器访问
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53'}
    print("--> 成功爬取网站信息")
    response = requests.get(url, headers=headers)  # 请求访问网站
    if response.status_code == 200:
        html = response.text  # 获取网页源码
        return html  # 返回网页源码
    else:
        print("获取网站信息失败!")
if __name__ == '__main__':
    # 创建workbook,就是创建一个Excel文档
    write_work = xlwt.Workbook(encoding='ascii')
    # 添加一张单
    write_sheet = write_work.add_sheet("sheet1")
    # 创建表头
   # write_sheet.write(0, 0, label='商品编号')      # 第1行 第1列 写入内容'商品编号'
    write_sheet.write(0, 0, label='商品名称')      # 第1行 第2列 写入内容'商品名称'
    write_sheet.write(0, 1, label='价格')         # 第1行 第4列 写入内容'价格'
    write_sheet.write(0, 2, label='详情页网址')         # 第1行 第5列 写入内容'商家'
    write_sheet.write(0, 3, label='评价数量')   # 第1行 第6列 写入内容'商品详情地址'
​
    # 记录当前行数
    _current_row = 0
    i=0
    k=0
    j=0
    # 搜索关键字
    keyword = input("请输入你要搜索的商品:")
    for k in range(0,10):
        i = 3+k*2
        j = 56+k*60
        # 搜索地址
        search_url = 'https://search.jd.com/Search?keyword=' + keyword + '&enc=utf-8&page={}&s={}&click=0'.format(i, j)
        print(search_url)
        html = get_html(search_url)
        # 初始化BeautifulSoup库,并设置解析器
        soup = BeautifulSoup(html, 'lxml')
        # 商品列表
        goods_list = soup.find_all('li', class_='gl-item')
        # 打印goods_list到控制台
        for li in goods_list:  # 遍历父节点
            # 由于我们第一行已经写入了表头。所以这里0+1,就是从第1行开始,后面每次循环+1
            _current_row += 1
            if _current_row == 29:
                break
            # 商品编号
            no = li['data-sku']
            # 商品名称
            name = li.find(class_='p-name p-name-type-2').find('em').get_text()
            # 价格
            price = li.find(class_='p-price').find('i').get_text()
            # 商家
            number = 'http:'+li.find(class_='p-commit').find('a')['href']
            # 商品详情地址
            co = li.find(class_='p-commit').find('a').get_text()
​
           #detail_addr = li.find(class_='p-name p-name-type-2').find('a')['href']
 # 写入Excel
            #write_sheet.write(_current_row, 0, label=no)
            write_sheet.write(_current_row, 0, label=name)
            write_sheet.write(_current_row, 1, label=price)
            write_sheet.write(_current_row, 2, label=number)
           # write_sheet.write(_current_row, 3, label=co)
​
    # 保存文件,使用的是相对目录(也可以使用绝对路径),会保存在当前文件的同目录下。文件名为读取多个商品页面1.xls,必须是.xls后缀
    write_work.save("./keyword.xls")

2.天猫:

from selenium import webdriver
import re
driver = webdriver.Chrome()
from selenium import webdriver
import time
import csv
import xlwt
​
# 搜索商品,获取商品页码
def search_product(key_word):
    # 定位输入框
    browser.find_element_by_id("q").send_keys(key_word)
    # 定义点击按钮,并点击
    browser.find_element_by_class_name('btn-search').click()
    # 最大化窗口:为了方便我们扫码
    browser.maximize_window()
    # 等待15秒,给足时间我们扫码
    time.sleep(15)
    # 定位这个“页码”,获取“共100页这个文本”
    page_info = browser.find_element_by_xpath('//div[@class="total"]').text
    # findall()返回的是一个列表,虽然此时只有一个元素它也是一个列表。
    page = re.findall("(\d+)", page_info)[0]
    return page
​
def main(key_word):
    book = xlwt.Workbook(encoding='utf-8', style_compression=0)
    sheet = book.add_sheet('爬取商品', cell_overwrite_ok=True)
    col = ('商品名称', '商品价格', '付款人数', '店铺名称','发货地')
    for i in range(0, 5):
        sheet.write(0, i, col[i])
    browser.get('https://www.taobao.com/')
    page = search_product(key_word)
    print(page)
    page_num = 1
    i=0
    while int(page) != page_num:
        print("*" * 20)
        print("正在爬取第{}页".format(page_num + 1))
        browser.get('https://s.taobao.com/search?q={}&s={}'.format(key_word, page_num * 44))
        browser.implicitly_wait(15)
​
        # 通过页面分析发现:所有的信息都在items节点下
        items = browser.find_elements_by_xpath('//div[@class="items"]/div[@class="item J_MouserOnverReq  "]')
        for item in items:
            # 参数信息
            pro_desc = item.find_element_by_xpath('.//div[@class="row row-2 title"]/a').text
            # 价格
            pro_price = item.find_element_by_xpath('.//strong').text
            # 付款人数
            buy_num = item.find_element_by_xpath('.//div[@class="deal-cnt"]').text
            # 旗舰店
            shop = item.find_element_by_xpath('.//div[@class="shop"]/a').text
            # 发货地
            address = item.find_element_by_xpath('.//div[@class="location"]').text
            with open('{}.csv'.format(key_word), mode='a', newline='', encoding='utf-8-sig') as f:
                csv_writer = csv.writer(f, delimiter=',')
                csv_writer.writerow([pro_desc, pro_price, buy_num, shop, address])
            sheet.write(i, 0, pro_desc)
            sheet.write(i, 1, pro_price)
            sheet.write(i, 2, buy_num)
            sheet.write(i, 3, shop)
            sheet.write(i, 4, address)
            i+=1
        page_num += 1
    path = 'D:/' + key_word + '.xls'
    book.save(path)
    print("数据爬取完毕!")
​
​
if __name__ == '__main__':
    key_word = input("请输入你要搜索的商品:")
    browser = webdriver.Chrome()
    main(key_word)

3.淘宝:

import re
import time
from concurrent.futures import ThreadPoolExecutor
import matplotlib.pyplot as plt
import pymysql
import requests
import seaborn as sns
import xlwt
from selenium import webdriver
import random
​
# 爬取网页部分
​
# 使用selenium自动获取cookie
# 因为解决不了淘宝滑块等验证的问题,此方法暂不可行
def getCookie():
    options = webdriver.Chrome
    dr = webdriver.Chrome(r'C:\Users\wpy\AppData\Local\Google\Chrome\Application\chromedriver_win32')
    dr.get('https://s.taobao.com/search?q=狗')
​
    cookie_test = dr.get_cookies()
    # 未整理的cookie
    print(cookie_test)
    cookie = [item["name"] + "=" + item["value"] for item in cookie_test]
    cookiestr = '; '.join(item for item in cookie)
    # 整理后的cookie
    print(cookiestr)
​
# 获取网页的html文档
# 具体思路是手动获取cookie,把cookie存入文件夹中,从文件夹中读取cookie进行爬取
def getHTML(name, page):
    try:
        # 爬取数据过多会导致淘宝安全系统认为我们是爬虫从而停止且ip被封,所以尝试使用代理池解决,首先使用付费代理,获取含有ip地址的api,然后把获取到的ip地址手动的存入程序中
        # proxy = ['106.32.9.201:4231', '58.63.37.245:4245', '27.156.212.245:4213', '218.91.4.107:4212',
        #          '117.57.20.217:4226', '222.190.198.122:4231', '123.158.127.209:4281']
        # # 准备好的代理ip
        # proxy1 = proxy[1]
        # new_data = {
        #     "http": "123.158.127.209:4281"
        # }
        start_url = 'https://s.taobao.com/search?q=' + name
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/70.0'
        }
        path = 'D:\mycookie.txt'
        with open(path, 'r') as f:
            mycookies = f.read()
        mycookies = mycookies.split(';')
        cookies = {}
        for cookie in mycookies:
            name, value = cookie.strip().split('=', 1)
            cookies[name] = value
        goods = ''
        for i in range(0, 1):
            i = int(page)
            if i == 0:
                url = start_url
            else:
                url = start_url + '&s=' + str(44 * i)
            # r = requests.get(url, headers=header, cookies=cookies, timeout=60,proxies=new_data)
            r = requests.get(url, headers=header, cookies=cookies, timeout=60)
            r.encoding = r.apparent_encoding
            goods += r.text
        print('获取网页文档成功!')
        return goods
    except:
        print('获取网页文档失败!' + '已爬取到第' + str(i) + '页')
​
​
# 解析网页部分
# 使用正则表达式匹配得到想要的字段,存储在列表中
def findMS(html):
    try:
        marketnames = re.findall('"nick":"(.*?)"', html)
        titles = re.findall('"raw_title":"(.*?)"', html)
        prices = re.findall('"view_price":"(.*?)"', html)
        pays = re.findall('"view_sales":"(.*?)"', html)
        data = []
        for i in range(len(titles)):
            data.append([marketnames[i], titles[i], prices[i], pays[i]])
        print('解析网页成功!')
        return data
    except:
        print('解析网页失败!')
​
​
# 数据处理部分
# 按照价格进行用户定制的升降序排序
# 升序
def sort1(data):
    for i in range(len(data) - 1):
        for j in range(len(data) - i - 1):
            if float((data[j])[2]) > float((data[j + 1])[2]):
                data[j], data[j + 1] = data[j + 1], data[j]
    return data
​
​
# 降序
def sort2(data):
    for i in range(len(data) - 1):
        for j in range(len(data) - i - 1):
            if float((data[j])[2]) < float((data[j + 1])[2]):
                data[j], data[j + 1] = data[j + 1], data[j]
    return data
​
​
# 数据持久化部分
​
# 存入Excel:
def download(data, name, page):
    try:
        if len(data) != page * 44:
            print("当前data元素个数为:" + str(len(data)))
            print("预期data元素个数为:" + str(page * 44))
            number = len(data)
        else:
            number = page * 44
        book = xlwt.Workbook(encoding='utf-8', style_compression=0)
        sheet = book.add_sheet('爬取商品', cell_overwrite_ok=True)
        col = ('商铺名称', '商品', '价格', '购买人数')
        for i in range(0, 4):
            sheet.write(0, i, col[i])
            for k in range(0, number):
                datalist = data[k]
                for j in range(0, 4):
                    sheet.write(k + 1, j, datalist[j])
        path = 'D:/' + name + '.xls'
        book.save(path)
        print('存入Excel成功!')
    except:
        print('存入Excel失败!')
​
​
# 存入mysql数据库:
def sql(name, data):
    try:
        # 获取连接对象conn,建立数据库的连接
        conn = pymysql.connect(host='localhost', port=3306, user='root', passwd='123456', db='dbcourses',
                               charset='utf8')
        # db:表示数据库名称
        #  进行连接数据库服务端(host 访问服务端的ip,user 访问服务端的用户,password访问服务端的用户密码,database 访问服务端的数据库,charset 访问时采用的编码方式)
        cur = conn.cursor()
        sql1 = 'create table ' + str(
            name) + '(id int not null,shop varchar(225),commodity varchar(225),price varchar(225),number varchar(225));'
        sql1 = str(sql1)
        cur.execute(sql1)
        # 二次拼接得到sql语句
        for i in range(0, len(data)):
            sql11 = 'insert into '
            sql22 = '(id,shop,commodity,price,number) values('
            sql33 = str(i)
            sql44 = ','
            sql55 = '"'
            sql77 = ');'
            sql66 = sql11 + name + sql22 + sql33 + sql44 + sql55 + str(data[i][0]) + sql55 + sql44 + sql55 + str(
                data[i][1]) + sql55 + sql44 + sql55 + str(data[i][2]) + sql55 + sql44 + sql55 + str(
                data[i][3]) + sql55 + sql77
            sql4 = str(sql66)
            cur.execute(sql4)
        conn.commit()
        cur.close()
        conn.close()
        print('存入数据库成功!')
    except:
        print('存入数据库失败!')
​
​
# 数据可视化部分
​
# 使用直方图表现价格趋势
def view(data):
    name = []
    price = []
    for i in range(len(data) - 1):
        name.append(i)
        price.append(data[i][2])
    # 用Matplotlib画条形图
    plt.bar(name, price)
    plt.show()
    # 用Seaborn画条形图
    sns.barplot(name, price)
    plt.show()
​
​
def main():
    # 用户输入
    name = input('请输入爬取商品的名字:')
    page = input('请输入你想要爬取的页数:')
    sort = input('请输入你想要的价格排序方式:升序请输入1,降序请输入2:')
    sort = int(sort)
    page = int(page)
​
    # 爬取数据
    data1 = []
    for i in range(0, int(page)):
        html = getHTML(name, page)
        data = findMS(html)
        # 猜测爬取数据过多被封,可能是爬取频率的问题,故此处随机设置间隔尝试解决此问题
        time.sleep(random.randint(1, 10))
        # print("当前数据长度为:" + str(len(data)))
        if len(data) == 0:
            print("数据有误!当前页数为" + str(i))
            print(data)
            print(html)
​
        data1 += data
        data = []
    # # 数据处理
    # if sort == 1:
    #     data = sort1(data)
    # if sort == 2:
    #     data = sort2(data)
​
    # 数据持久化
    download(data1, name, page)
    # sql(name, data)
​
    # 数据可视化
    # view(data)
​
​
# 创建线程池:提高爬取的效率
if __name__ == "__main__":
    pool = ThreadPoolExecutor(max_workers=2)
    future1 = pool.submit(main())
    pool.shutdown()