【Python爬虫】按时爬取京东几类自营手机型号价格参数并存入数据库

一、最近刚好想换手机,然后就想知道京东上心仪的手机价格如何,对比手机价格如何,以及相应的历史价格,然后就用Python requests+MySQLdb+smtplib爬取相关的数据

二、关于实现的主要步骤:
1、根据京东搜索页面,搜索某型号(如小米手机)的自营手机,得出该型号在京东自营上的链接url
2、根据该url,将小米手机的京东自营的所有种类的url均爬取下来,存在列表或者字典里
3、根据找到的所有商品的url,爬取商品对应的价格,商品的简介
4、将以上相关信息插入数据库,并根据数据库下一条目与上一条目的价格对比,若产品降价了,则发相关email到指定用户进行通知

三、Python实现

1、如何获得京东自营的某型号手机的大类url:

首先,在京东自营上搜索某手机时,出现的结果列表并不会显示该品牌手机的所有型号手机,如可能会显示小米5 黑色32G,但可能不会显示小米5 白色 32G这一型号,这一型号在我们点击小米5 黑色32G链接进入下一级页面后会有相应的链接,所以我们第一步先要爬出所有该品牌的大类链接,再由大类链接去找到所有的该品牌的所有机型。

脚本实现如下:调用webdriver的PhantonJS, 进行JS渲染,从而得到页面的html,再运用正则判断商店名是否为该品牌的自营手机店,从而确定抓取哪些url

 def get_href_list(self, search_url, shop_name):

    '''得到京东某品牌自营的各种乐视手机的型号大类的url列表'''

    dv = webdriver.PhantomJS()
    a = search_url
    dv.get(a)
    time.sleep(4)
    html = dv.execute_script("return document.documentElement.outerHTML")
    aa = open('tey.txt','w+')
    aa.write(html)
    aa.close()
    bb = open('tey.txt' , 'r+')
    bbb = bb.read()
    bb.close()
    re_cmp = re.compile('
  • ', re.S) re_cmp_shop2 = re.compile('(.*?)', re.S) cc = re.findall(re_cmp , bbb) aa = open('tey_1.txt','w+') for i in cc: aa.write(i + '\n') aa.close() return_href_list = [] dd= re.findall(re_cmp_shop, bbb) aa = open('tey_2.txt','w+') print 'url is %s, shop name is %s'%(search_url,shop_name) for jj in range(len(dd)): ddd = re.findall(re_cmp_shop2, dd[jj]) if len(ddd) !=0 and ddd[0] == shop_name : return_href_list.append('https://item.jd.com/' + cc[jj] + '.html') aa.write(ddd[0] + '\n' + 'https://item.jd.com/' + cc[jj] + '.html' + '\n\n') aa.close() self.return_list = return_href_list return return_href_list
  • 2、抓到大类url后,需要进一步根据大类url,抓取该品牌所以机型Url,及相应的价格,简介等。首先也是对大类中的每个url进行JS渲染,再根据正则表达式抓取相应的简介,价格是抓包发现由特定的url进行交互实现的价格数值的传递,因此对该url进行调用即可得到特定机型的价格,(参数为特定机型的京东item id),最后将所有的信息存入一个列表中。
    def get_href_info(self, href_list):

        '''用来根据给定的大类url来找出相对应的所有不同型号的乐视手机的url及对应的规格说明及相应的价格'''
    
        final_href = []
        final_return_result = []
        count = 0
        for single_href_list in href_list:
            count += 1
            try:
                dv = webdriver.PhantomJS()
                a = single_href_list
                dv.get(a)
                time.sleep(4)
                html = dv.execute_script("return document.documentElement.outerHTML")
    
                aa = open('leshi_%s.txt'%count,'w+')
                aa.write(html)
                aa.close()
                re_compile_info = re.compile('
    (.*?)
    ', re.S) full_info = re.findall(re_compile_info, html)[0] re_compile = re.compile('colorSize: (.*?)],', re.S) cc = re.findall(re_compile, html)[0] except: dv = webdriver.PhantomJS() a = single_href_list dv.get(a) time.sleep(4) html = dv.execute_script("return document.documentElement.outerHTML") aa = open('leshi_%s.txt'%count,'w+') aa.write(html) aa.close() re_compile_info = re.compile('
    (.*?)
    ', re.S) full_info = re.findall(re_compile_info, html)[0] re_compile = re.compile('colorSize: (.*?)],', re.S) cc = re.findall(re_compile, html)[0] re_compile1 = re.compile('{(.*?)}', re.S) ccc = re.findall(re_compile1, cc) if len(ccc[0]) == 0: info_list = [] info_list.append(full_info) info_list.append(re.findall(re.compile('.com/(.*?).html' ,re.S), a)[0]) final_href.append(info_list) else: re_item_id_compile = re.compile('"SkuId":(.*?),', re.S) for i in ccc: item_id = re.findall(re_item_id_compile, i)[0] re_compile_info = re.compile('
    (.*?)
    ', re.S) html = urllib.urlopen('https://item.jd.com/' + item_id + '.html') html = html.read() full_info = re.findall(re_compile_info, html)[0] info_string = full_info info_list = [] info_list.append(info_string) info_list.append(item_id) final_href.append(info_list) aa = open('leshi.txt','w+') for kk in final_href: hhhh = [] print kk[0] print kk[1] try_time = 10 while try_time>0: try: a = ['https://p.3.cn/prices/mgets?type=1&pduid=1557983493&pdpin=&pdbp=0&skuIds=J_','https://p.3.cn/prices/mgets?type=1&pduid=1557983493&pdbp=0&skuIds=J_', 'https://p.3.cn/prices/mgets?type=1&pduid=1557983493&skuIds=J_', 'https://p.3.cn/prices/mgets?type=1&area=1_72_4137_0&pdtk=&pduid=1557983493&pdpin=&pdbp=0&skuIds=J_'] aaa = a[random.randint(0,4)] + str(kk[1]) b=urllib.urlopen(aaa) c=b.read() d=eval(c) kk.append(d[0]['p']) break except: try_time = try_time - 1 print 'fail %s time in href %s'%((10 -try_time), str(kk[1])) time.sleep(random.randint(1,3)) if len(kk) == 2: kk.append('Not captured') aa.write(kk[0] + ' ' + 'https://item.jd.com/' + str(kk[1]) + '.html' + ' ' + kk[2]) aa.write('\n\n') hhhh.append(str(kk[1])) hhhh.append(kk[0]) hhhh.append(kk[2]) hhhh.append('https://item.jd.com/' + str(kk[1]) + '.html') hhhh.append( time.strftime("%Y-%m-%d,%H:%M:%p", time.localtime())) final_return_result.append(hhhh) aa.close() self.return_list = final_return_result return final_return_result

    3、调用Mysql数据库将相关数据插入数据库:
    使用的MySQLdb数据库,需要注意以下几点:
    (1)、注意数据库的编码,默认为latin编码,这对中文编码是会存在异常的,需要将其修改为utf-8编码,具体修改是在MYSQL的配置文件里,就不赘述了;
    (2)、MYSQL插入表时不支持变量插入,需要自己实现做好处理,表名的各事业有相关要求
    (3)、执行语句时,如插入语句,对变量的格式(带”的字符创或不带”的整型)需要自己多留意

    def connect_sql(self, data_list, databse_name,):
        '''将爬到的相关数据插入数据库'''
    
        conn = MySQLdb.connect(host = 'localhost', user = 'root', passwd = '', charset = 'utf8')
        cur = conn.cursor()
        database_create = 'create database if not exists %s'%databse_name
        cur.execute(database_create)
        conn.select_db(databse_name)
        table_name = 'price_' + time.strftime("%Y_%m_%d_%H_%M_%p", time.localtime())
        cur.execute('create table %s (item_id varchar(20) primary key not null, machine_name varchar(100),machine_price varchar(50),item_url varchar(50), time varchar(50))'%table_name)
        conn.commit()
        for ii in data_list:
            try:
                insert_sql = 'insert ignore %s values(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\')'%(table_name, ii[0], ii[1].decode('gbk').encode('utf-8'), ii[2], ii[3], ii[4])
                cur.execute(insert_sql)
            except:
                insert_sql = 'insert ignore %s values(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\')'%(table_name, ii[0], ii[1].encode('utf-8'), ii[2], ii[3], ii[4])
                cur.execute(insert_sql)
            conn.commit()
        cur.close()
        conn.close()
    

    4、邮件通知事件:
    从数据库的表中select数据,得到价格,与之前时间的价格对比,若有降价,发送email
    msg = MIMEMultipart()
    msg[‘from’] = ‘**@163.com’
    msg[‘to’] = ‘***@qq.com’
    email_info = u’%s 降价了,现在价格是%s 元,速速买’%(name, aaa[0][0])
    msg[‘subject’] = Header(email_info,’utf-8’)
    server = smtplib.SMTP(‘smtp.163.com’)
    server.login(‘@163.com’,’***’)
    error=server.sendmail(msg[‘from’], msg[‘to’],msg.as_string())
    server.close

    5、之后的定时爬取价格:
    第一次完成爬取数据后,之后需要定时的爬取价格,由于手机型号,url,简介等都在第一次已经确定了,故而之后只需要根据这些信息去爬取可能会变化的价格就OK了,所以写了个函数实现价格爬取
    根据爬去的商品的京东id,去调用京东的特定url,返回价格,并在数据库建立新表,插入数据库,其他的插入项如id等则等同于之前。

    def get_price(self, all_info_list,databse_name):
        '''根据数据库已有的一个表数据来爬下一个时间的商品价格'''
    
        cur_time = time.strftime("%Y_%m_%d_%H_%M_%p", time.localtime())
        agen_list = ['Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0', 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0','Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko)', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0']
        hea ={
        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0',
        'Host':'p.3.cn',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3','Accept-Encoding':'gzip, deflate','Content-Length':'94'
        }
        for i in all_info_list:
            item_id = i[0]
            try_time = 10
            while try_time>0:
                try:
                    a = ['https://p.3.cn/prices/mgets?type=1&pduid=1557983493&pdpin=&pdbp=0&skuIds=J_','https://p.3.cn/prices/mgets?type=1&pduid=1557983493&pdbp=0&skuIds=J_', 'https://p.3.cn/prices/mgets?type=1&pduid=1557983493&skuIds=J_', 'https://p.3.cn/prices/mgets?type=1&area=1_72_4137_0&pdtk=&pduid=1557983493&pdpin=&pdbp=0&skuIds=J_']
                    aa = a[random.randint(0,4)] + str(item_id)
                    hea['User-Agent'] = agen_list[random.randint(0,4)]
                    b=requests.get(aa, headers=hea)
                    c=b.text
                    d=eval(c)
                    i[2] = d[0]['p']
                    i[4] = cur_time
                    break
                except:
                    try_time = try_time - 1
                    time.sleep(random.randint(1,3))
                    print 'fail %s time in href %s'%((10 - try_time),i[3])
            if try_time == 0:
                i[2] = 'Not captured'
        self.connect_sql(all_info_list,databse_name)   
    

    你可能感兴趣的:(【Python爬虫】按时爬取京东几类自营手机型号价格参数并存入数据库)