Python爬取数据并存入MongoDB

最近和朋友一起开发APP,需要大量数据,而"互联网"与"共享"融合发展的理念,遂资源的可重用给予了当代骚客文人获得感与幸福感…好了,不日白了(正宗重庆话,吹牛的意思),开始正题

BeautifulSoup4

本人是做JavaWeb的,可能多多少少还是遗留了Java的一些格式及规范,但爬虫千千万,却是Python最好使

  1. Beautiful Soup4作为HTML/XML的解析器,其使用、解析难度都较为简单;
  2. 人性化的API,支持 lxml 的 XML解析器;
  3. 同样也支持CSS选择器、Python标准库中的HTML解析器;
  4. 在整个DOM树中,能够快速定位到理想位置节点,并获取相应的内容;
  5. 自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码;
  6. 安装:pip install beautifulsoup4

Selenium + ChromeDriver与Requests

  1. Selenium是一个用于Web应用程序测试的开源自动化工具。直接运行在浏览器中,就像真正的用户在操作一样。而对于爬虫来讲,可视化的界面加模拟用户操作,简直是质的提升。
  2. ChromeDriver - WebDriver for Chrome,WebDriver是一个开源工具,用于在许多浏览器上自动测试webapps。它提供了导航到网页,用户输入,JavaScript执行等功能。ChromeDriver是一个独立的服务,它为 Chromium 实现 WebDriver 的 JsonWireProtocol 协议。
  3. Requests模块比urllib2模块更简洁,支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。在python内置模块的基础上进行了高度的封装,从而使得python进行网络请求时,变得人性化。
  4. selenium安装:pip install selenium
  5. ChromeDriver安装:下载地址:http://chromedriver.storage.googleapis.com/index.htmlhttps://npm.taobao.org/mirrors/chromedriver/
    (1)首先解压压缩包
    (2)找到chromedriver.exe并复制到你的项目中的venv\Lib\site-packages\selenium\webdriver\chrome中
  6. Requests安装:pip install requests

消息头与代理IP以及请求频率

作为爬虫(非用户操作),是一定要学会伪装自己,不然仅仅是写代码测试的时候,多搞几下,人家网站的反爬措施就会冻结你一段时间,那就直接玩鸟了。

  1. 消息头:一般就是针对于headers中的User-Agent,如果没有对headers进行设置,User-Agent会声明自己是python脚本,而遭到网站的拒绝。
    修改自己的headers可以将自己的爬虫脚本伪装成浏览器的正常访问,从而避免这一问题。
# 较常见的headers
headers = {
	'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36'
}
# 或者你心情好,也可以搞个完善的headers,like this
headers = {
	'Accept': '*/*',
	'Accept-Language': 'en-US,en;q=0.8',
	'Cache-Control': 'max-age=0',
	'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
	'Connection': 'keep-alive',
	'Referer': 'http://www.baidu.com/'
}
  1. 设置代理IP:我们可以想象程序的运行速度是非常快的,当我们用爬虫获取某个网站的数据时,一个固定IP的访问频率远超人为操作的标准(即使你单身几十年,也不可能在几ms内,进行如此频繁的访问),所以网站一般会设置一个IP访问频率的阈值,一旦超出,就证明这是机器在搞骚操作。
    推荐西刺代理IP
proxy = {'http':'106.46.136.112:808'}
  1. 请求频率:通俗点也可以是访问次数。前面提到,以非人为操作的频率访问别人的网站,本身这对于服务器来讲是一种压力,作为爬虫,应该尽量避免这种荒唐的事情发生,所以,适当减少自己的请求次数与请求节奏,对你对服务器,都是百利而无一害的。
    最简单的做法,可以让你的程序休息一会儿
import time
time.sleep(3000)

MongoDB

在此要感谢我的朋友TH,起初我只知道MongoDB这几个英文字母,是他作为引路人和实践者,让我认知到又一门技术,非常感谢你的引导!

  1. MongoDB是一个内存数据库,对数据的操作大部分都在内存中,支持冷/热数据处理,是一个基于分布式文件存储的开源数据库系统,在高负载的情况下,添加更多的节点,以保证服务器性能。
  2. 将数据存储为一个文档(即可以存放 xml、json、bson 类型的数据),数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
  3. 由此可见,相比较 MySQL,MongoDB 以一种直观文档的方式来完成数据的存储。它很像 JavaScript 中定义的 JSON 格式,不过数据在存储的时候 MongoDB 数据库为文档增加了序列化的操作,最终存进磁盘的其实是一种叫做 BSON 的格式,即 Binary-JSON。
  4. 存储方式为虚拟内存+持久化。支持大容量的存储,适合文件、图片等数据。
  5. MongoDB安装:https://www.mongodb.com/download-center/community;下载适合你操作系统及版本的安装包,具体流程可以百度。语法及使用具体操作,在这里就不做概述。

最后献上代码,有误或可以调优的地方,还请留言指出,一定虚心接受

# -*- coding:utf-8 -*-
import json
import re
import time
import random
import requests
import pymongo
import bson.binary
from selenium import webdriver
from bs4 import BeautifulSoup


BASE_URL = "https://music.xxx.com"
HEADER = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"
    }

class GetData():

    def __init__(self):
        # 建立MongoDB数据库连接
        client = pymongo.MongoClient('192.168.31.68', 27017)
        # 连接所需数据库
        db = client["song"]
        # 连接所需集合
        self.lyric = db["lyric"]
        self.picture = db["picture"]


    @staticmethod
    def get_driver():
        """  获取Chrome driver """
        # 进入阅览器
        options = webdriver.ChromeOptions()
        # 设置header
        options.add_argument('user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"')
        # 加载chromedriver.exe
        chrome_driver = r"D:\myProject\worker\venv\Lib\site-packages\selenium\webdriver\chrome\chromedriver.exe"
        driver = webdriver.Chrome(executable_path=chrome_driver, chrome_options=options)
        return driver

    @staticmethod
    def get_chrome(driver, url):
        """  获得HTML页面内容 """
        time.sleep(random.randint(10, 30))  # 主线程随机暂停 10至30秒
        driver.get(url)
        iframe = driver.find_elements_by_tag_name('iframe')[0]
        driver.switch_to.frame(iframe)
        return BeautifulSoup(driver.page_source, "lxml")

    @staticmethod
    def get_request(url):
        """  封装request的GET请求 """
        time.sleep(random.randint(10, 30))  # 主线程随机暂停 10至30秒
        data = requests.get(url, headers=HEADER)
        return data

    @staticmethod
    def get_lrc(song_id):
        """  解析拼装歌词 """
        lrc_url = 'http://music.xxx.com/api/song/lyric?' + 'id=' + str(song_id) + '&lv=1&kv=1&tv=-1'
        html = GetData.get_request(lrc_url).text

        # 转换为json
        j = json.loads(html)

        # 英文歌词
        lrc = j['lrc']['lyric']
        # 中文歌词
        cn_lrc = j['tlyric']['lyric']

        # 正则去掉[]及里面内容
        pat = re.compile(r'\[.*\]')
        lrc = re.sub(pat, "", lrc)
        cn_lrc = re.sub(pat, "", cn_lrc)
        # 获得英文和中文歌词
        lrc = lrc.strip()
        cn_lrc = cn_lrc.strip()

        a = lrc.split("\n")
        b = cn_lrc.split("\n")

        result = ""
        for index_en in range(len(a)):
            for index_cn in range(len(b)):
                if index_en == index_cn:
                    result += a[index_en] + "\n" + b[index_en] + "\n"

        return result


    def get_netease_cloud(self, count):
        driver = GetData.get_driver()
        # 只搜索类型为欧美的歌曲
        url = BASE_URL + "/#/discover/playlist/?order=hot&cat=欧美&limit=35&offset=" + str((0 + count) * 35)
        soup = GetData.get_chrome(driver, url)

        # img_html = soup.find_all('img', class_=re.compile('j-flag'))
        # img_data = GetData.get_request(img_html[count]['src'])

        # 过滤class为msk的a标签,检索出每张专辑ID及访问路径
        msg = soup.find_all('a', class_=re.compile('msk'))

        for playlist in msg:
            """ 单张专辑的歌曲目录 """
            url = BASE_URL + playlist['href']
            soup = GetData.get_chrome(driver, url)
            # 获取table列表中播放按钮的ID值
            play = soup.find_all('span', class_=re.compile('ply'))

            for play_id in play:
                try:
                    url = BASE_URL + "/song?id=" + play_id['data-res-id']
                    soup = GetData.get_chrome(driver, url)

                    # 获取图片
                    song_img = soup.find_all('img', class_=re.compile('j-img'))
                    song_img_data = GetData.get_request(song_img[0]['data-src']).content

                    # 歌名
                    song_name = soup.find_all('em', class_=re.compile('f-ff2'))
                    # 歌手名与所属专辑
                    singer, album = soup.find_all('p', class_=re.compile('des s-fc4'))

                    pat = re.compile('>(.*?)<')
                    pat_song_name = ''.join(pat.findall(str(song_name[0])))
                    pat_singer = ''.join(pat.findall(str(singer)))
                    pat_album = ''.join(pat.findall(str(album)))

                    result = "歌名:" + pat_song_name + "\n" + pat_singer + "\n" + pat_album + "\n" + GetData.get_lrc(
                        play_id['data-res-id'])

                    self.picture.save(dict(
                        song_name=pat_song_name,
                        img=bson.binary.Binary(song_img_data)
                    ))

                    self.lyric.save(dict(
                        song_name=pat_song_name,
                        singer=pat_singer,
                        album=pat_album,
                        lyric=result
                    ))
                except Exception as e:
                    print(e)
                    pass
                continue

        driver.quit()


if __name__ == '__main__':
    count = 0
    lic = GetData()
    while(count < 38):
        lic.get_netease_cloud(count)
        count += 1

  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值