“数据入库之MongoDB(案例二:爬取拉勾)”的版本间的差异

来自CloudWiki
跳转至: 导航搜索
搜索城市页面
第135行: 第135行:
 
为了拿到某个城市的搜索结果,并验证是否有30页(如果有的话,还需要顺便拿到该城市下面的行政区列表),我们还需要继续获取搜索结果的城市页面。以北京为例,使用上面的方法访问链接:
 
为了拿到某个城市的搜索结果,并验证是否有30页(如果有的话,还需要顺便拿到该城市下面的行政区列表),我们还需要继续获取搜索结果的城市页面。以北京为例,使用上面的方法访问链接:
  
https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?city=%E5%8C%97%E4%BA%AC&cl=false&fromSearch=true&labelWords=&suginput=,确实可以拿到北京的搜索结果首页,在该页面上也能找到结果的总页数30以及北京所有的行政区划。
+
  https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?city=%E5%8C%97%E4%BA%AC&cl=false&fromSearch=true&labelWords=&suginput=
 +
 
 +
,确实可以拿到北京的搜索结果首页,在该页面上也能找到结果的总页数30以及北京所有的行政区划。
 +
 
 
===爬取单页数据===
 
===爬取单页数据===
  

2019年7月11日 (四) 10:12的版本

Python爬虫(入门+进阶) DC学院

本节课程的内容是MongoDB数据库及其界面化工具RoboMongo的安装和基本使用,并且通过爬取拉勾的例子讲授如何通过pymongo包把爬取到的数据存储在MongoDB数据库中。

MongoDB

什么是MongoDB

MongoDB是一个高性能,开源,无模式的文档型数据库

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成

MongoDB相关的安装

Windows的安装方法:

小歪老师在自己的知乎专栏[MongoDB及可视化工具的安装]中给出了详细的MongoDB数据库、可视化工具RoboMongo和MongoDB的PyCharm插件——Mongo Plugin的安装步骤和方法,可按照步骤安装并测试连接

Python用于操作MongoDB的第三方库pymongo安装:

pip install pymongo


Mac OS的安装方法

参考Mac OSX 平台安装 MongoDB安装,可视化工具RoboMongo安装方法与Windows平台大致相同。

MongoDB的PyCharm插件——Mongo Plugin安装: Preferences——Plugins——Mongo Plugin,安装完成后重启PyCharm可发现右侧有Mongo Explorer

Python用于操作MongoDB的第三方库pymongo安装

 pip install pymongo

测试连接

首先需要使用以下方法在终端启动MongoDB

cd /usr/local/mongodb/bin
sudo ./mongod


然后在PyCharm右侧的Mongo Explorer连接localhost:27017即可


Linux系统的安装方法

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-4.0.0.tgz

tar xf mongodb-linux-x86_64-rhel62-4.0.0.tgz

mv mongodb-linux-x86_64-rhel62-4.0.0 /usr/local/mongod

echo "export PATH=$PATH:/usr/local/mongod/bin" >> /etc/profile

source /etc/profile

mkdir -p /data/db #创建暑假目录

mongod

MongoDB管理命令

如果你需要进入MongoDB后台管理,你需要先打开mongodb装目录的下的bin目录,然后执行mongo命令文件。

MongoDB Shell是MongoDB自带的交互式Javascript shell,用来对MongoDB进行操作和管理的交互式环境。

当你进入mongoDB后台后,它默认会链接到 test 文档(数据库):

cd /usr/local/mongod/bin
./mongo

MongoDB在Python中的基本使用

通过一个简单的例子展示使用pymongo连接MongoDB数据库,并插入数据

#! /usr/bin/env python
# -*- coding:utf-8 -*-
from pymongo import MongoClient
client = MongoClient()
db = client.test #连接test数据库,没有则自动创建
my_set = db.set #使用set集合,没有则自动创建
my_set.insert({'name':'Vinie','age':24})#插入一条数据

插入的数据可在MongoDB的test数据库的set集合中找到

实战环节

爬取拉勾网有关“爬虫”的职位信息,并把爬取的数据存储在MongoDB数据库中

  1. 首先前往拉勾网“爬虫”职位相关页面
  2. 确定网页的加载方式是JavaScript加载
  3. 通过谷歌浏览器开发者工具分析和寻找网页的真实请求,确定真实数据在position.Ajax开头的链接里,请求方式是POST
  4. 使用requests的post方法获取数据,发现并没有返回想要的数据,说明需要加上headers
  5. 加上headers的’Cookie’,’User-Agent’,’Referer’等信息,成功返回数据
  6. 再把返回的对应数据存储到MongoDB

准备工作

pip3 install bs4

pip3 install lxml

打印城市名

第一步:模拟发送请求,尝试抓取数据。带上请求头和参数,发送 POST 请求,只会得到如下的结果:

{"status":false,"msg":"您操作太频繁,请稍后再访问","clientIp":"xxx.xxx.xxx.xxx","state":2402}

这说明拉勾网的反爬措施是对 Cookies 有要求的。Cookies 是从浏览器端生成的,但是要从网站的 JavaScript 代码分析出 Cookies 的生成方式,无疑是一件很复杂的事情。这个问题先暂且按下,先考虑把拉勾网支持的所有城市的城市名拉下来,可以找到城市列表页的链接是:https://www.lagou.com/jobs/allCity.html ,只需要带上含有 Accept, Referer 和 User-Agent 三个 Key 的请求头发送 GET 请求,就可以拿到页面的 HTML 代码,使用 BeautifulSoup 解析页面即可获取城市列表

import requests
from bs4 import BeautifulSoup

headers = {
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Referer': 'https://www.lagou.com/jobs/list_%E8%BF%90%E7%BB%B4?city=%E6%88%90%E9%83%BD&cl=false&fromSearch=true&labelWords=&suginput=',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
url = "https://www.lagou.com/jobs/allCity.html?keyword=数据分析&px=default&city=全国"
s = requests.Session()
rsp = s.get(url, headers=headers, verify=False)
doc = rsp.text
soup = BeautifulSoup(doc, 'lxml')
alphabet_list = soup.find_all("ul", class_="city_list")
city_list = []
for alpha in alphabet_list:
    cities = alpha.find_all("li")
    for city in cities:
        city_name = city.a.string
        city_list.append(city_name)
print(city_list)

结果:

['安阳', '安庆', '鞍山', '澳门特别行政区', '安康', '北京', '保定', '蚌埠', '北海                                                                                        ', '包头', '滨州', '巴音郭楞', '保山', '亳州', '宝鸡', '巴中', '巴彦淖尔', '白城                                                                                        ', '本溪', '成都', '长沙', '重庆', '常州', '长春', '沧州', '常德', '赤峰', '潮州                                                                                        ', '承德', '郴州', '滁州', '朝阳', '东莞', '大连', '德州', '东营', '德阳', '大庆                                                                                        ', '达州', '大同', '大理', '儋州', '德宏', '丹东', '定西', '迪庆', '恩施', '鄂尔                                                                                        多斯', '鄂州', '佛山', '福州', '阜阳', '抚州', '抚顺', '防城港', '广州', '贵阳',                                                                                         '桂林', '赣州', '广安', '贵港', '广元', '甘孜藏族自治州', '杭州', '合肥', '哈尔                                                                                        滨', '惠州', '海口', '呼和浩特', '湖州', '淮安', '邯郸', '衡阳', '河源', '黄石',                                                                                         '海外', '怀化', '衡水', '菏泽', '黄山', '淮北', '黄冈', '淮南', '红河', '呼伦贝                                                                                        尔', '汉中', '鹤壁', '哈密', '贺州', '河池', '鹤岗', '济南', '金华', '嘉兴', '江                                                                                        门', '济宁', '揭阳', '荆州', '吉林', '晋中', '九江', '吉安', '焦作', '景德镇', '                                                                                        荆门', '锦州', '酒泉', '晋城', '金昌', '鸡西', '佳木斯', '昆明', '开封', '克拉玛                                                                                        依', '喀什', '廊坊', '兰州', '洛阳', '临沂', '柳州', '拉萨', '聊城', '临汾', '龙                                                                                        岩', '乐山', '吕梁', '泸州', '漯河', '连云港', '六安', '丽水', '丽江', '娄底', '                                                                                        六盘水', '凉山彝族自治州', '莱芜', '辽阳', '林芝', '绵阳', '马鞍山', '茂名', '梅                                                                                        州', '眉山', '牡丹江', '南京', '宁波', '南昌', '南宁', '南通', '南充', '南阳', '                                                                                        宁德', '南平', '内江', '莆田', '濮阳', '攀枝花', '萍乡', '盘锦', '平顶山', '青岛                                                                                        ', '泉州', '秦皇岛', '清远', '衢州', '庆阳', '钦州', '曲靖', '黔西南', '齐齐哈尔                                                                                        ', '黔南', '日照', '深圳', '上海', '苏州', '沈阳', '石家庄', '绍兴', '汕头', '宿                                                                                        迁', '三亚', '商丘', '汕尾', '上饶', '韶关', '十堰', '宿州', '邵阳', '三明', '松                                                                                        原', '三门峡', '遂宁', '三沙', '四平', '绥化', '商洛', '朔州', '天津', '太原', '                                                                                        唐山', '台州', '泰州', '泰安', '台北', '天门', '天水', '铜川', '吐鲁番', '铜仁',                                                                                         '通化', '铁岭', '通辽', '武汉', '无锡', '温州', '乌鲁木齐', '潍坊', '芜湖', '威                                                                                        海', '渭南', '武威', '梧州', '吴忠', '文山', '乌兰察布', '西安', '厦门', '徐州',                                                                                         '新乡', '西宁', '邢台', '香港特别行政区', '咸阳', '湘潭', '襄阳', '许昌', '信阳                                                                                        ', '孝感', '咸宁', '宣城', '湘西土家族苗族自治州', '忻州', '新余', '烟台', '银川                                                                                        ', '盐城', '扬州', '宜昌', '岳阳', '榆林', '运城', '宜宾', '玉溪', '宜春', '云浮                                                                                        ', '永州', '阳江', '营口', '玉林', '益阳', '延安', '雅安', '延边', '伊犁', '鹰潭                                                                                        ', '阳泉', '郑州', '珠海', '中山', '湛江', '株洲', '镇江', '肇庆', '淄博', '张家                                                                                        口', '漳州', '遵义', '舟山', '驻马店', '周口', '长治', '枣庄', '自贡', '资阳', '                                                                                        张家界', '昭通']

搜索城市页面

为了拿到某个城市的搜索结果,并验证是否有30页(如果有的话,还需要顺便拿到该城市下面的行政区列表),我们还需要继续获取搜索结果的城市页面。以北京为例,使用上面的方法访问链接:

 https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?city=%E5%8C%97%E4%BA%AC&cl=false&fromSearch=true&labelWords=&suginput=

,确实可以拿到北京的搜索结果首页,在该页面上也能找到结果的总页数30以及北京所有的行政区划。

爬取单页数据

#! /usr/bin/env python
# -*- coding:utf-8 -*-

from pymongo import MongoClient
import requests

client = MongoClient()
db = client.lagou #创建一个lagou数据库
my_set = db.job #创建job集合

url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E6%88%90%E9%83%BD&needAddtionalResult=false'
payload = {
    'first':'true',
    'pn':'1',
    'kd':'爬虫',
}

headers = {
    'Cookie':'',
    'User-Agent':'',
    'Referer':'',
} #填入对应的headers信息

response = requests.post(url, data = payload, headers = headers) #使用POST方法请求数据,加上payload和headers信息
print(response.json())
my_set.insert(response.json()['content']['positionResult']['result']) #把对应的数据保存到MOngoDB

爬取多页数据

定义一个函数爬取多页的数据;使用fake-Agent包随机选取User-Agent

#! /usr/bin/env python
# -*- coding:utf-8 -*-

import requests
from pymongo import MongoClient
import time
from fake_useragent import UserAgent

client = MongoClient()
db = client.lagou
lagou = db.PHP #创建PHP集合

headers = {
            'Cookie':'',
            'Referer':'',
        } #对应的headers信息

def get_job_info(page, kd): #加入一个职位参数kd
    for i in range(page):
        url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false&isSchoolJob=0'
        payload = {
            'first': 'true',
            'pn': i,
            'kd': kd,
        }

        ua = UserAgent() 
        headers['User-Agent'] = ua.random #使用fake-Agent随机生成User-Agent,添加到headers
        response = requests.post(url, data=payload, headers=headers)

        if response.status_code == 200:
            job_json = response.json()['content']['positionResult']['result']
            lagou.insert(job_json)
        else:
            print('Something Wrong!')

        print('正在爬取' + str(i+1) + '页的数据...')
        time.sleep(3)

if __name__ == '__main__':
    get_job_info(3, 'PHP') #爬取前3页的PHP职位信息

课后作业:

   安装MongoDB、RoboMongo可视化工具、Mongo Plugin插件、pymongo包
   尝试爬取多个职位数据
   改进爬虫,爬取详情页数据

补充资料 1. MongoDB

       前往MongoDB 3.4 中文文档,学习更多关于MongoDB语法的知识
       可以在Github的PyMongo中学习到更多pymongo包的用法

2. POST请求

       阅读更加复杂的 POST 请求,学习关于requests的POST请求方法的用法

3. fake-useragent包

       前往fake-useragent 0.1.7官方文档学习更多fake-useragent的用法

4. 爬取微博热点评论

ModeHeader是很好的测试httpheader,支持在线修改http header的小工具。我们可以用它来模拟移动端的Request Headers。下面将为大家展示如何添加此扩展程序。 使用Chrome浏览器,访问扩展程序:chrome://extensions/,点击获取更多扩展程序。(注意这里需要翻墙)

Alt text 搜索ModHeader

Alt text

点击添加至Chrome

Alt text

右上角点开它,添加名字和User-Agent

Alt text

接下来就可以用它去爬取移动端的应用数据了。 下面是爬取手机端的微博热评数据,大家可以学习一下。

import pymongo import requests import pandas as pd

class weibo:

   def __init__(self):
       # 初始化爬取条数
       self.count = 0
       #实例化mongo client连接对象
       # client = pymongo.MongoClient('127.0.0.1', 27001)
       # self.coll = client['spider']['weibo']
   def write_mongo(self,item):
       将item写入数据库中
       self.coll.update({'id': count},{'$set': item}, upsert=True)
       print ('已入库:', self.count, '条。')
       self.count += 1
   def write_file(self, item):
       将item写入到文件中
       # 写入文件
       df = pd.DataFrame.from_dict(item,orient='index')
       df.to_csv('./weibo.csv')
   def get_info(self):
       comment = {}
       for i in range(1,11):
           url = 'https://m.weibo.cn/single/rcList?format=cards&id=4160547165300149&type=comment&hot=1&page={}'.format(i)
           #创建Headers,cookie和user_agent需要换成自己的
           headers = {
               'Cookie':'_T_WM=a759aca8fd5fd4e20cbf876930d6ee91; H5_wentry=H5; backURL=https%3A%2F%2Flogin.sina.com.cn%2Fsso%2Flogin.php%3Furl%3Dhttps%3A%2F%2Fm.weibo.cn%2F%26_rand%3D1509006100.3267%26gateway%3D1%26service%3Dsinawap%26entry%3Dsinawap%26useticket%3D1%26returntype%3DMETA%26sudaref%3D%26_client_version%3D0.6.26; SCF=Aoy6fc80dcpiX-IQbgAI9tL-MQ91qWXakLPbJUlZgUbpCQaX3yqGci9_RUtAh6HGAhJukUqNqn5Cw28oR5h00t8.; SUB=_2A2509dQuDeRhGeNN61UT-S7LyDWIHXVUGfxmrDV6PUJbktBeLWnykW0W2p_Y0olCbF4MlLyQ_ooUjClbyg..; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W5TIMn1sFAPOAnJGH2adIyi5JpX5K-hUgL.Fo-0ehME1K5Ne0.2dJLoI7feIgUQUGUDUs4LMNSk; SUHB=0rr76wcx9aInWq; H5:PWA:UID=1',
               'Host':'m.weibo.cn',
               'qq':'MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1',
               'referer':'https://m.weibo.cn/single/rcList?id=4160547165300149&type=comment&hot=1&tab=1',
               'Upgrade-Insecure-Requests':'1',
               'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
           }
           res = requests.get(url,headers = headers,verify = False).json()
           #选取名字和评论,生成字典
           for index in range(len(res[-1]['card_group'])):
               comment[res[-1]['card_group'][index]['user']['screen_name']] = res[-1]['card_group'][index]['text']
               self.count += 1
               print('已爬取:', self.count, '条。')
       #调用写文件函数,写进文件
       self.write_file(comment)
       #调用数据库函数,写进MongoDB数据库
  1. self.write_mongo(comment)

if __name__ == '__main__':

   # 实例化weibo类,生成wb实例
   wb = weibo()
   # 调用get_info方法
   wb.get_info()

参考文档:

[1] https://www.cnblogs.com/zhangxinqi/p/9242687.html

[2] https://mp.weixin.qq.com/s?__biz=MzI5MTM2Njk3Mg==&mid=2247483901&idx=1&sn=852359e0bf9eafe4db6cc0604eb9abf4&chksm=ec10f0aedb6779b8324142b737bd7ebd86256ecd9176944e43dc0876290d559017695ee7acf8&mpshare=1&scene=23&srcid=0707eHGwZjFACjwiyEDVXXHL#rd