我的第一次爬网页经历

来源:互联网 发布:js图片旋转动画 编辑:程序博客网 时间:2024/05/15 14:32

背景

之前我从来没有爬过网页,一直对scrapy很好奇,这周一粽子让我去爬一下http://www.calltrace.cn/home.html的
工单管理-》已提交结果工单-》举报内容摘要/来电时间,一共有100多条,看起来需要一条一条点开才行。
我之前对网页有了一点小小的积累,大致明白了cookie,post,get,html这方面的知识,因此觉得应该是能够胜任的,因此就愉快得答应了下来。

不过我一开始走了不少弯路,最后抓出网页信息的时候,也是瞎猫碰到死耗子,并不能说以后就能成功了,而且或许这个换台电脑,关闭一下浏览器未必能够成功。
我的学习路线大致是这样的:

1、我先查看了网页源码和调试模式下的element元素审查

    然后我就发现源码里面并没有完整的信息嘛,只是一个html的骨架
    而element里面的信息到时全面的,因此我一开始想着是不是应该把网页整体拉下了,然后去解析html,把数据提取出来,而后的实践我发现至少我这次用半天时间没有做出来。

2、于是我一开始的方法是:学些久仰大名的scrapy,然后我大致了解了scrapy的原理:

    几个教程:
    http://kongtianyi.cn/2016/09/27/python/Scrapy-Lesson-2/(我先学这个)
    http://blog.csdn.net/yancey_blog/article/details/53887606
    扒的网址:http://www.heartsong.top/forum.php?mod=viewthread&tid=8
    xpath语法
    http://www.runoob.com/xpath/xpath-syntax.html
    request的高级用法
    http://www.891010.com/1449.html
  • spider把response里面的数据提取出来,要不返回item,要不进行下一次请求
  • Items是用来存储数据,就是一个model
  • pipelines 负责对spider返回数据的处理
  • 其它的如中间件,settings我没怎么用到,就不说了
    其中最重要的是yield语法,在scrapy里面,它会产生新的线程,或者保存item,或者给出下一个请求

3、但是,在学了这些之后,我发现完全用不到这次要爬的网站,因为上面的爬虫基于url进行爬取,不过我

要爬的网站里面并没有url。。。后来我看到一个词,叫动态网页,可能说的就是这个
    我只能去查看chrom里面的network,看看是否有get和post请求了,后来我看到了2个请求:
url_frontpage = "http://www.calltrace.cn/Entity/List.do"
url_detail = "http://www.calltrace.cn/Entity/Detail.do"


它们中一个是主页的请求,一个是详情页的请求
主页请求List.do的request中带有参数page,limit,start;response中则返回指定数量的已提交工单的编号
详情页请求Detail.do中请求参数则正好需要上面的已提交工单的编号!
因此,只要先请求List.do,把所有已提交工单的编号都拿到,然后用这个编号请求Detail.do就能获得详情页的所有信息了。


我在postman上试了一下,又填了一个坑:该网站是需要登录的,因此要用cookie访问这些接口,但postman没找到填cookie的地方,后来我又上网搜了一下,发现只要打开postman的拦截器就行了,它会自动把chrome浏览器的cookie填进来

于是,代码就很容易写了,这其中对关键字段的定位,我用了找规律的本办法,想来这样也没关系,顺带处理了异常和多线程访问
# -*- coding: utf-8 -*-import threadingimport requestsimport jsoncookies = {"JSESSIONID": "D4746970BB45A3A27AE9567C0E02DE32",  # 该sessionid是会变化的           "rememberme": "true",           "company": "%E5%B7%A5%E4%BF%A1%E9%83%A8",           "username": "yudongsheng",           "password": "63275050"}url_frontpage = "http://www.calltrace.cn/Entity/List.do"url_detail = "http://www.calltrace.cn/Entity/Detail.do"limit = "500"  # 每页展示的工单条数count = 0  # 输出的是第几个工单def get_url_list():    """    调用List.do接口,获取所有已提交结果工单的id,构成一个列表返回    :return:    """    querystring = {"_dc":"1488702544010",                   "entityInfoId":"a9f19f47e32940ae920d144982f52af1",                   "filterSql":"",                   "roleId":"x8c8feb4f37b40be8e41626afbd8ee1c",  # 固定值                   "filterViewId":"x625053ea86b453c9ee0f5c629c48a5b",  # 固定值                   "originalViewId":"x625053ea86b453c9ee0f5c629c48a5b",  # 固定值                   "menuId":"x7f2acbbd6e44f888ee25340944b0d4b",  # 固定值                   "limit":limit,"page":"1","start":"0"}  # 一页展示的工单数    headers = {        'cache-control': "no-cache",        'postman-token': "677a27f7-5545-3d25-c503-65d6c2f5d378"        }    response = requests.request("GET", url_frontpage, headers=headers, params=querystring, cookies=cookies)  # 访问列表接口,获取工单ids    ret1 = json.loads(response.text)    entityRecordIds = [ele["tjjgGongdanRwgdidFk"]for ele in ret1["data"]]    return entityRecordIdsdef get_jubaoneirongzhaiyao(entityRecordId):    """    传入工单id,调用Detail.do接口,获得工单详情    :param entityRecordId:    :return:    """    global count    querystring = {"entityInfoId": "daf39beb648143219d2ccbffc9ab94b8",                   "entityRecordId": entityRecordId,                   "filterViewId": "",                   "roleId": "x8c8feb4f37b40be8e41626afbd8ee1c",                   "specificCompanyId": "",                   "specificSolutionId": "",                   "menuId": ""}    payload = ""    headers = {        'cache-control': "no-cache",        'postman-token': "d1aa3193-a9df-bcbe-361b-8310c4c59df7"    }    response = requests.request("POST", url_detail, data=payload, headers=headers, params=querystring, cookies=cookies)    text = response.text    ret = json.loads(text)    # 建议下面一段代码加个锁,这样可以防止乱序    count += 1    print(u"第"+str(count)+u"条")    try:        print(ret["recordName"]+u"   举报内容摘要   "+ret['sectionList'][1]["items"][2]["items"][0]["value"])  # 获取任务编号和举报内容摘要    except:        print ret.get("recordName", u"未知错误  "+ "id:  "+entityRecordId)+u"  举报内容摘要"+u"  空   "#def multi_thread_url():    """    多线程获取数百个详情页的信息    :return:    """    entityRecordIds = get_url_list()    print(u"总共有" + str(len(entityRecordIds)) + u"条")    for entityRecordId in entityRecordIds:        t =threading.Thread(target=get_jubaoneirongzhaiyao, args=(entityRecordId,))        t.start()multi_thread_url()
最后的输出如下图所示:

4、不足

    首先没有进一步了解scrapy,跳过了其中的难点,对于动态网页,应该有其他方式来抓取
    其次可以做一个自动登录的动作,把cookie取到,就不用手动改cookie了
    然后可以把下载的数据保存到excel里面去
    最后,要能够在windows下运行





0 0
原创粉丝点击