美文网首页
Python 实战:week2 实战作业

Python 实战:week2 实战作业

作者: 超net | 来源:发表于2016-05-31 22:11 被阅读3096次

    结果:

    > show dbs
    bj58     0.001GB
    ganji    0.011GB
    local    0.000GB
    xiaozhu  0.000GB
    > use ganji
    switched to db ganji
    > show collections
    detailinfo
    links
    > db.links.find().count()
    61988
    > db.links.find()[0]
    {
        "_id" : ObjectId("574c361be002825f0b42c431"),
        "url" : "http://biz.click.ganji.com/bizClick?url=pZwY0jCfsvFJshI6UhGGshPfUiqzIy78ph-6UMwd0v6ds1DOPWELnjmLPW-3sh6YURkknj7DEYw7EbEOPHcQEWD3wDmvPNuanNEYrHDkPWN3wbDYEdkknj70njTQsRkknjDznj0vPjn1gjTknHDYgjTknHDOPWELnjmLPW-0njTQn1ckgjTknHnQrRkknjDQn1-0njTQnHF0njTQnHEvPjmQnWnLrj0dP7kknjDQgjTknHD1nRkknj7BpywbpyOMgjTknH70njTQnHbkP1mkrjwxPRqkudkknjDkgjTknRkknjDkgjTknHEOsW9OsWcvsWckrRkknj7PULGGUAQ6s1N8naTCHy7WpyOYULPCrzKFUMw-UaKPmyn9Hdn9yaTQn7tQn7td2iKK0ZK_uRI-mbVGIatdn108n1m92DVcRDdnsaK_pyV-cDI-mvVf2iKjpZFfUyNfPHT8na3zPWmQsWDknBKHmyu60hbfPHnLsWnvxRkknjDdrHI0njTQsH70njTQsH70njTQEv6zUvd-gjTknyDdmhEzrj9YsHEOrjDVPAcQuBYOmvE1sHcQPHnQmhEkrynkPE&v=2"
    }
    > db.detailinfo.find().count()
    60765
    > db.detailinfo.find()[6198]
    {
        "_id" : ObjectId("574c8677e002826842500b08"),
        "title" : "露得清水活盈透旅行装乳霜15克+保湿水20ML - 20元",
        "url" : "http://bj.ganji.com/meironghuazhuang/1808653812x.htm",
        "price" : 20,
        "location" : [
            " 北京",
            "丰台",
            "科技园区"
        ],
        "date" : "03-05 09:23",
        "condition" : null,
        "goods_type" : "护肤品"
    }
    >
    

    作业项目地址

    总结

    • 如何判断是否是最后一页

    两种实现思路

    1,是否有分页符

    if detail_soup.find("ul","pageLink"):
    
    if detail_soup.select(".pageLink"):
    

    如果没有,pass

    2,是否元素数量足够

    如果没有,同样 pass

    • li元素

    js-item加载?

    课上老师点了一下,没明白……

    • 爬取的小技巧

    应对网站对ip的请求限制,使用proxies

    http://cn-proxy.com/

    random.choice(list)

    大网站承压性很好,可以不在请求间设置间隔,但对同一个ip的请求频次有限制

    • 不抓商家帖子

    因为永远存在,不知道什么时候交易成功的

    • 判断是否已经交易成功

    交易成功的物品已经下架,爬取时需要跳过

    找一个不存在的页面 ,查看有无不同可以进行判断

    • 断点续传

    在详细页的信息集合中添加详情页的 url 字段

    用爬取列表页获得的url数据 减 已经爬取的详情页中的 url ,取子集

    db_urls = [item['url'] for item in info_links.find()]
    item_urls = [item['url'] for item in info_detail.find()]
    result_urls = set(db_urls) - set(item_urls)
    
    • 抓取类目,乱码
    url = "http://bj.ganji.com/wu/"
    
    web_data = requests.get(url)
    # print web_data.encoding   # 查看编码类型
    # ISO-8859-1
    

    修改

    web_data.encoding = "utf-8"

    • 内容提取

    有几处比较折腾

    1,发布时间

    页面呈现

    05-30 发布

    html

    <i class="pr-5">
                05-30 发布                  </i>
    

    列表化,可以看出字符的编码

        if date_exist.get('class')[0] == "pr-5":  # 不是都有发布时间
            date = date_exist.get_text().strip().split(u'\xa0')[0]   # 获取元素内容,去除两边空格,用中间的不间断空格分割为列表
    

    strip 删除前后空格

    不间断空格 u'\xa0'

    2,成色

    html

    <li>
        <label>新旧程度:</label>
              全新,可送货(赠床垫 | 有床头柜 | 有床箱 | 有抽屉)      
    </li>
    

    .stripped_strings获取所有下级元素的内容,形成列表

    condition = list(detail_soup.select(".second-det-infor.clearfix li")[0].stripped_strings)
    

    打印列表

    [u'\u65b0\u65e7\u7a0b\u5ea6\uff1a', u'\u5168\u65b0\uff0c\u53ef\u9001\u8d27\uff08\u8d60\u5e8a\u57ab | \u6709\u5e8a\u5934\u67dc | \u6709\u5e8a\u7bb1 | \u6709\u62bd\u5c49\uff09']
    

    获取列表的第二个元素

    condition = list(detail_soup.select(".second-det-infor.clearfix li")[0].stripped_strings)[1]

    得到

    全新,可送货(赠床垫 | 有床头柜 | 有床箱 | 有抽屉)

    ','做分割符,获取第一个元素

    condition = list(detail_soup.select(".second-det-infor.clearfix li")[0].stripped_strings)[1].split(','.decode("utf-8"))[0]
    print condition
    

    最终结果

    全新

    3,交易地点

    <ul class="det-infor">
          <li>
              <label>类  型:</label>
              <span>          
                <a href="/shafachaji/" target="_blank">沙发</a>
              </span>
          </li>
          <li>
             
              <label>价  格:</label>
                  <i class="f22 fc-orange f-type">3</i>元<i class="line">|</i>
                  <span class="f12 fc-gray">参考价格:100-699元</span>
                  <a target="_blank" gjalog="100000000013000100000010" href="http://www.ganji.com/hangqing/?mod=detail&to=devalue&url=shafachaji" class="p-z-type">近期价格走势<i class="p-z-icon"></i></a>      
          </li>
          <li>
                <label>交易地点:</label> 
                <a href="/jiaju/" target="_blank"> 北京 </a> - <a href="chaoyang/" target="_blank">朝阳</a>
          </li>
    

    尽量在爬取的时候将数据变得规整

    如果用stripped_strings,会将子元素的内容、子元素间的内容也弄进来

    >>> location = list(detail_soup.select(".det-infor li")[2].stripped_strings)
    >>> print location                                      
    >>> [u'\u4ea4\u6613\u5730\u70b9\uff1a', u'\u5317\u4eac', u'-', u'\u671d\u9633']
    
    .det-infor li [0] # 类型
    .det-infor li [1] # 价格
    .det-infor li [2] # 交易地点
    

    可以获取 ul 父元素下第三个 li 元素 下的所有 a 子元素

    <li>
        <label>交易地点:</label> 
        <a href="/jiaju/" target="_blank"> 北京</a> -
       <a href="beijingzhoubian/" target="_blank">北京周边</a>
    </li>
    
    detail_soup.select('ul.det-infor > li:nth-of-type(3) > a')
    
    ul.det-infor > li:nth-of-type(1) # 类型
    ul.det-infor > li:nth-of-type(2) # 价格
    ul.det-infor > li:nth-of-type(3) # 交易地点
    

    用 map 和 lambda 函数,对列表中每一项获取元素内容,再用 list 制成列表

    list(map(lambda x:x.text,detail_soup.select('ul.det-infor > li:nth-of-type(3) > a')))
        #wrapper > div.content.clearfix > div.leftBox > div:nth-child(3) > div > ul > li:nth-child(3)
        # print location[0], location[1]
    

    地点可能不止一个元素,就使用列表存储

    • 选择器

    ul.det-infor > li:nth-of-type(3) > aul.det-infor > li:nth-child(3) >a

    BeautifulSoup 不识别通过 google 开发者工具获取的CSS选择器nth-child(第几个子元素而且是特定元素),可以用nth-of-type(第几个特定元素)替换。

    通过 google 开发者工具获取的CSS选择器:

    #wrapper > div.content.clearfix > div.leftBox > div:nth-child(3) > div > ul > li:nth-child(3) > a:nth-child(2)

    两者的区别:

    the-difference-between-nth-child-and-nth-of-type

    两次尝试:

    >>> location = list(map(lambda x:x.text,detail_soup.select('ul.det-infor > li:nth-child(3) > a')))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/chao/Desktop/projects/web_crawler/venv-foo/lib/python2.7/site-packages/bs4/element.py", line 1481, in select
        for candidate in _use_candidate_generator(tag):
      File "/Users/chao/Desktop/projects/web_crawler/venv-foo/lib/python2.7/site-packages/bs4/element.py", line 1442, in recursive_select
        for i in tag.select(next_token, recursive_candidate_generator):
      File "/Users/chao/Desktop/projects/web_crawler/venv-foo/lib/python2.7/site-packages/bs4/element.py", line 1400, in select
        'Only the following pseudo-classes are implemented: nth-of-type.')
    NotImplementedError: Only the following pseudo-classes are implemented: nth-of-type.
    
    >>> location = list(map(lambda x:x.text,detail_soup.select('ul.det-infor > li:nth-of-type(3) > a')))
    >>> print location
    [u' \u5317\u4eac', u'\u671d\u9633']
    >>> 
    

    对于:nth-of-type(3),之前一直很疑惑,但没有去进一步了解,这次查了一下,原来这属于 CSS3 中定义的选择器,属性、id、div>p这些是 CSS1、2 中定义的

    CSS 选择器参考手册

    • 可迭代的对象

    可以通过 for 循环 或 list() 处理

    • 数字应该转为 数值 再存入数据库

    否则不能搜索,抓取下来也没有意义

    • 导入模块

    只导入函数,不导入 集合 ,可以?

    导入,即使是 from ... import ... ,都会运行模块所有顶层代码

    其他模块虽然没法直接调用,但函数内部可以调用

    • 怎么将大量详情页的 url 传递给函数,并使用多进程?

    我多虑了,几万数据的读取还是很轻松的

    • 爬虫效率

    如果是单核电脑,多进程不会有效,甚至降低效率。如果单核,多进程 效率低于 多线程。否则,进程效率高于线程

    页面解析速度,lxml 库,速度是 beautiful 的 10 倍

    import lxml

    lxml

    网络请求速度,异步非阻塞

    • using-pymongo-with-multiprocessing
    /Users/chao/Desktop/projects/web_crawler/venv-foo/lib/python2.7/site-packages/pymongo/topology.py:75: UserWarning: MongoClient opened before fork. Create MongoClient with connect=False, or create client after forking. See PyMongo's documentation for details: http://api.mongodb.org/python/current/faq.html#using-pymongo-with-multiprocessing>
      "MongoClient opened before fork. Create MongoClient "
    
    http://api.mongodb.com/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient
    
    • 奇特的页面链接

    常见的的:

    http://bj.ganji.com/jiaju/2043426190x.htm
    

    但是,也会有以下两种……

    http://m.zhuanzhuan.58.com/Mzhuanzhuan/zzWebInfo/zzganji/zzpc/detailPc.html?infoId=736841308648177667&cateId=107&fullCate=107&fullLocal=1&zzfrom=ganjiweb&zhuanzhuanSourceFrom=722
    
    http://biz.click.ganji.com/bizClick?url=pZwY0jCfsvFJshI6UhGGshPfUiqBmyOMUvOMs1ckrjc3n1TYPjK3sh6YURkknjDkPHmOrND3Pj-jnjmYEY7jP1KjE1TzEHcYnbE1nH6APRkknj70njTQsRkknjDvP1NLP1T3nH60njTQnHw0njTQnWT3nW91njEYn7kknjDvn7kknjDvn7kknjDQPj60njTQnHF0njTQnHEvPjN3PjnLP1NOnRkknjDzn7kknjDQn170njTQmh-buA-8udkknjDQgjTknHDOnj0vnj9Yg16x0AI0njTQn7kknj70njTQn7kknjDQnHc8nWn8nB3Ln7kknj7PULGGUAQ6s1N8naTCHy7WpyOYULPCrzKFUMw-UaKPmyn9Hdn9yaTQn7tQn7td2iKK0ZK_uRI-mbVGIatdn108n1m92DVcRDdnsaK_pyV-cDI-mvVf2iKjpZFfUyNfPHT8na3zPWmQsWDknBKHmyu60hbfPHnLsWnvxRkknjDdrjw0njTQsH70njTQsH70njTQEv6zUvd-gjTknyNkrH9vrj-6sH01nWEVPjbYuBY3P1c3synzPW6-nyu6nyFhrT&v=2
    

    页面爬取规则不同,导致出错

    http://m.zhuanzhuan.58.com/Mzhuanzhuan/zzWebInfo/zzganji/zzpc/detailPc.html?infoId=736841308648177667&cateId=107&fullCate=107&fullLocal=1&zzfrom=ganjiweb&zhuanzhuanSourceFrom=722
      File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 558, in get
        raise self._value
    IndexError: list index out of range
    
    • 获取详情

    有的页面,有时获取详情会失败,有时成功

    加了个延时

    • 不同页面的获取

    分别单独尝试 每个类目的列表页、几种可能的详情页url、详情页不同的规则爬取方式的制定

    • 从集合读取文档

    读取文档的顺序是随机的

    相关文章

      网友评论

          本文标题:Python 实战:week2 实战作业

          本文链接:https://www.haomeiwen.com/subject/ewfhdttx.html