美文网首页
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