Python爬虫实战笔记_2 去赶集

爬二手商品信息的流程共分两步:
第一步:爬取各商品的url, 保存到数据表itemurls中。此过程采用多进程方式。
第二步:从itemurls表中读出商品url, 爬取商品的详细信息。

源代码

main.py

  • 由于各类目下的商品页数相差较大,没有像爬58时使用get_page_urls()时传一个固定的页数去爬取,而是在insert_urls_by_nav()中用一个变量flag作标志位。当前页面如果没有抓到商品信息,则认为爬到了最后一页,终止整个类目的爬取。另一个好处是被网站反爬时也能及时终止爬取,避免不停抓回来无效页面
  • spiderurls() 完成流程的第一步
  • spideriteminfo() 完成流程的第二步
#!/usr/bin/python
# -*- coding: UTF-8 -*

#  multiprocess
#  a spider goes to ganji.com
#  step1 get item urls and insert them into database

from multiprocessing import Pool
import time
import pymongo
import re

from bs4 import BeautifulSoup
import requests

from urlhandler_ganji import get_nav_urls, get_page_urls, get_item_urls
from mongoconn import mongoset, mongoinsert


table = mongoset('ganji', 'itemurls')
table.create_index([('itemurl', pymongo.DESCENDING)], unique=True)

tinfo = mongoset('ganji', 'iteminfo')
tinfo.create_index([('url', pymongo.DESCENDING)], unique=True)

def listtodict(urls):
    datamany = []
    for itemurl in urls:
        data = {
            'itemurl': itemurl
        }
        datamany.append(data)
    return datamany

def insert_urls_by_nav(navurl):
    flag = True
    pid = 1
    filteritem = 'div.layoutlist > dl > dt > a'
    filtervalid = 'ul.pageLink'
    while flag:
        pageurl = navurl+'o{}'.format(pid)
        itemurls = get_item_urls(pageurl, filteritem, filtervalid)
        if itemurls:
            mongoinsert(table, listtodict(itemurls))
            pid += 1
            #table.insert_many(listtodict(itemurls))
        else:
            flag = False
        time.sleep(8)

### step1
def spiderurls():
    pool = Pool()
    url = 'http://sh.ganji.com/wu/'
    urlbase = 'http://sh.ganji.com'
    filternav = 'div.main-pop dt a'
    navurls = ['http://sh.ganji.com/shouji/', 'http://sh.ganji.com/shoujihaoma/', 'http://sh.ganji.com/shoujipeijian/', 'http://sh.ganji.com/bijibendiannao/', 'http://sh.ganji.com/taishidiannaozhengji/', 'http://sh.ganji.com/diannaoyingjian/', 'http://sh.ganji.com/wangluoshebei/', 'http://sh.ganji.com/shumaxiangji/', 'http://sh.ganji.com/youxiji/', 'http://sh.ganji.com/xuniwupin/', 'http://sh.ganji.com/jiaju/', 'http://sh.ganji.com/jiadian/', 'http://sh.ganji.com/zixingchemaimai/', 'http://sh.ganji.com/rirongbaihuo/', 'http://sh.ganji.com/yingyouyunfu/', 'http://sh.ganji.com/fushixiaobaxuemao/', 'http://sh.ganji.com/meironghuazhuang/', 'http://sh.ganji.com/yundongqicai/', 'http://sh.ganji.com/yueqi/', 'http://sh.ganji.com/tushu/', 'http://sh.ganji.com/bangongjiaju/', 'http://sh.ganji.com/wujingongju/', 'http://sh.ganji.com/nongyongpin/', 'http://sh.ganji.com/xianzhilipin/', 'http://sh.ganji.com/shoucangpin/', 'http://sh.ganji.com/baojianpin/', 'http://sh.ganji.com/laonianyongpin/', 'http://sh.ganji.com/gou/', 'http://sh.ganji.com/qitaxiaochong/', 'http://sh.ganji.com/xiaofeika/', 'http://sh.ganji.com/menpiao/']
    navurls = get_nav_urls(url, urlbase, filternav)
    print(navurls)
    #insert_urls_by_nav(navurls[0])
    pool.map(insert_urls_by_nav, navurls)

def get_soup(url):
    proxies = {'http': "207.62.234.53:8118"}
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
    #source = requests.get(url, proxies=proxies, headers=headers)
    source = requests.get(url)
    soup = BeautifulSoup(source.text, 'lxml')
    return soup

def getemtext(element):
    try:
        text = element.get_text().strip().replace('\t', '').replace('\n', '').replace(' ','')
    except:
        text = ''
    return text

def getmultitest(element):

    text = map(getemtext, element)
    info = ''
    for t in text:
        info = info + ' ' + t
    return info

def get_target_info(url):
    soup = get_soup(url)
    if soup.select('div.error'):
        msg = soup.select('div.error p')[0]
        pattern = re.compile('删除')
        if pattern.search(getemtext(msg)):
            curtime = time.localtime()
            data = {
                'url': url,
                'saletime': curtime
            }
            try:
                tinfo.updata_one({'url': url}, {'$set', data})
            except:
                pass
    else:
        title = soup.select('h1.title-name')
        pubtime = soup.select('i.pr-5')
        detailinfo = soup.select('ul.det-infor > li')
        category = detailinfo[0].select('a')  # soup.select('ul.det-infor > li > span > a')
        price = detailinfo[1].select('i')  # soup.select('ul.det-infor i.fc-orange')
        address = detailinfo[2].select('a')
        data = {
            "title": getemtext(title[0]),  # .get_text(),#.get_text().decode('gbk'),
            "pubtime": getemtext(pubtime[0]), #.split()[0],  # .strip(u'发布'),#.get_text(),
            "price": getemtext(price[0]),  # .get_text(),
            "category": getmultitest(category), #getemtext(category[0]) + ' ' + getemtext(category[1]),
            "address": getmultitest(address),
            'url': url,
            'saletime': ''
        }
        try:
            tinfo.insert_one(data)
        except:
            pass

###step2
def spideriteminfo():
    turl = mongoset('ganji', 'itemurls')
    pattern = re.compile(r'sh.ganji.com')
    urls = turl.find()
    for url in urls:
        if pattern.search(url['itemurl']):
            print(url)
            get_target_info(url['itemurl'])
            time.sleep(1)

if __name__ == '__main__':
    ###step1
    ###step2
    

优化后的urlhandler_ganji.py

  • 给get_nav_urls(), get_item_urls()等函数添加了‘filter'参数,调用的时候传入要提取的元素路径, 这样爬不同的网页可以通用
#!usr/bin/env python
#_*_ coding: utf-8 _*_
#
#  functions to get item urls

from bs4 import BeautifulSoup
import requests
import time

from mongoconn import mongoset, mongoinsert


def get_soup(url):
    proxies = {'http': "207.62.234.53:8118"}
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
    #source = requests.get(url, proxies=proxies, headers=headers)

    source = requests.get(url)
    soup = BeautifulSoup(source.text, 'lxml')
    return soup

def combineurls(url, page):
    pageurls = []
    for i in range(1, page+1):
        pageurl = url.format(i)
        pageurls.append(pageurl)
    return pageurls

def get_nav_urls(url, urlbase, filter):
    soup = get_soup(url)
    navlist = soup.select(filter)
    absurls = []
    for submnu in navlist:
        try:
            absurl = urlbase + submnu.get('href')
        except TypeError:
            pass
        except:
            pass
        if absurl not in absurls:
            absurls.append(absurl)
    return absurls

def get_page_urls(urlbase, suburl, pagenum=100):
    #  get urls with pages id
    pageurls = []
    for i in range(1, pagenum + 1):
        pageurl = (urlbase + suburl).format(i)
        pageurls.append(pageurl)
    return pageurls

def listtodict(urls):
    datamany = []
    for itemurl in urls:
        data = {
            'itemurl': itemurl
        }
        datamany.append(data)
    return datamany

def get_item_urls(url, filter, filtervalid=''):
    soup = get_soup(url)
    print(url)
    itemurls = []
    if len(soup.select(filtervalid)):
        itemlist = soup.select(filter)
        if len(itemlist):
            for item in itemlist:
                try:
                    itemurl = item.get('href')
                except:
                    pass
                itemurls.append(itemurl)
        #time.sleep(1)
    return itemurls

def getemtext(element):
    return element.get_text().strip().replace('\t', '').replace('\n', '').replace(' ','')

def get_urls_by_nav(navurl):
    navurls = get_page_urls(navurl)
    for pageurl in navurls:
        itemurls = get_item_urls(pageurl)
    return itemurls

if __name__ == '__main__':

    url = 'http://sh.58.com/sale.shtml'
    get_nav_urls(url)

运行结果
2016-07-02 16:55:22
...
http://sh.ganji.com/dianyingpiao/o87/
http://sh.ganji.com/qitaxiaochong/o84/
http://sh.ganji.com/dianyingpiao/o88/
http://sh.ganji.com/dianyingpiao/o89/
http://sh.ganji.com/qitaxiaochong/o85/
http://sh.ganji.com/qitaxiaochong/o86/
http://sh.ganji.com/dianyingpiao/o90/
http://sh.ganji.com/qitaxiaochong/o87/
http://sh.ganji.com/qitaxiaochong/o88/
http://sh.ganji.com/qitaxiaochong/o89/
http://sh.ganji.com/qitaxiaochong/o90/
2016-07-02 16:58:18
数据表

[itemurls]


Screen Shot 2016-07-08 at 7.20.28 AM.png

[iteminfo]


Screen Shot 2016-07-09 at 9.25.04 AM.png
总结
  • 爬的过程中不停被反爬,最后把sleep时间设为8秒才顺利爬完
  • 爬到5万多商品的url
  • 商品信息共爬到18199个, 这是因为筛选掉了那些不是ganji商品的页面
  • 接下来需要重复执行这个爬虫, 已便获取到商品的‘saletime’更新到数据表中
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容