爬取人民网新闻数据

源代码

main.py

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
from lxml import etree
from mongodb_save import save_data
import time
from multiprocessing import Pool


class Spider1():
    def __init__(self, t, link):
        self.t = t
        self.link = link

    def spider1(self, num):
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        options.add_argument('user-agent='
                             'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
        drivers = webdriver.Chrome(options)
        drivers.set_page_load_timeout(300)  # 根据页面实际需要加载时间设置
        drivers.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
            'source': 'Object.defineProperty(navigator, "webdriver", {get:()=>undefined})'
        })
        try:
            drivers.get(self.link + 'index{i}.html#fy01'.format(i=num))
            wait = WebDriverWait(drivers, 10)
            inputs = wait.until(
                EC.presence_of_all_elements_located(
                    (By.XPATH, '//div[contains(@class, "headingNews")]/div[contains(@class, "hdNews")]/div[@class="on"]')))
            texts = wait.until(
                EC.presence_of_all_elements_located(
                    (By.XPATH,
                     '//div[contains(@class, "headingNews")]/div[contains(@class, "hdNews")]/div[@class="on"]/em/a')))
            for input, text in zip(inputs, texts):
                html = input.get_attribute('outerHTML')
                href = re.search('<h5>\s*<a href="(.*?)".*?>.*?</a>\s*</h5>', html).group(1)
                #print('http://' + self.link.split('//')[1].split('/')[0] + href)
                title = re.search('<h5>\s*<a.*?>(.*?)</a>\s*</h5>', html).group(1)
                content = text.get_attribute("innerText")
                html = etree.HTML(html)
                if html.xpath('//div/a'):
                    img = html.xpath('//div/a/img/@src')
                    #print('http://' + self.link.split('//')[1].split('/')[0] + img[0])
                else:
                    img = 'Zero'
                    #print(img)
                save_data(self.link, href, title, content, img)
            print(self.t, '第' + str(num) + '页')
        except Exception as e:
            print(self.t, '第' + str(num) + '页', e)
            f = open('error.txt', 'a', encoding='utf-8')
            f.write(self.t + '第' + str(num) + '页' + str(e))
            f.close()

class Spider2():
    def __init__(self, t, link):
        self.t = t
        self.link = link

    def spider2(self, num):
        options = webdriver.ChromeOptions()
        options.add_argument('--headless')
        options.add_argument('user-agent='
                            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
        drivers = webdriver.Chrome(options)
        drivers.set_page_load_timeout(300)  # 根据页面实际需要加载时间设置
        drivers.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
            'source': 'Object.defineProperty(navigator, "webdriver", {get:()=>undefined})'
        })
        try:
            drivers.get(self.link + 'index{i}.html#fy01'.format(i=num))
            wait = WebDriverWait(drivers, 10)
            inputs = wait.until(
                EC.presence_of_all_elements_located(
                    (By.XPATH, '//div[@class="headingNews"]/div[contains(@class, "hdNews")]/p')))
            texts = wait.until(
                EC.presence_of_all_elements_located(
                    (
                        By.XPATH, '//div[@class="headingNews"]/div[contains(@class, "hdNews")]/p/em/a')))
            for input, text in zip(inputs, texts):
                html = input.get_attribute('outerHTML')
                href = re.search('<strong>\s*<a href="(.*?)".*?>.*?</a>\s*</strong>', html).group(1)
                #print('http://' + self.link.split('//')[1].split('/')[0] + href)
                title = re.search('<strong>\s*<a.*?>(.*?)</a>\s*</strong>', html).group(1)
                content = text.get_attribute("innerText")
                html = etree.HTML(html)
                if html.xpath('//p/a'):
                    img = html.xpath('//p/a/img/@src')
                    #print('http://' + self.link.split('//')[1].split('/')[0] + img[0])
                else:
                    img = 'Zero'
                    #print(img)
                save_data(self.link, href, title, content, img)
            print(self.t, '第' + str(num) + '页')
        except Exception as e:
            print(self.t, '第' + str(num) + '页', e)
            f = open('error.txt', 'a', encoding='utf-8')
            f.write(self.t + '第' + str(num) + '页' + str(e))
            f.close()

def main():
    option = webdriver.ChromeOptions()
    option.add_argument('--headless')
    option.add_argument('user-agent='
                        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
    driver = webdriver.Chrome(option)
    driver.set_page_load_timeout(300)  # 根据页面实际需要加载时间设置
    driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
        'source': 'Object.defineProperty(navigator, "webdriver", {get:()=>undefined})'
    })
    driver.get('http://www.people.com.cn/')
    wait = WebDriverWait(driver, 10)
    inputs = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//ul[@class="cf"]//div[@class="xinwen"]//a')))
    element = dict()
    for input in inputs:
        t = input.get_attribute("innerText")
        link = input.get_attribute('href')
        element[t] = link
    start = time.time()
    pool = Pool()                       #创建进程池
    for v in element.keys():
        t = v
        link = element[v]
        if link.split('//')[1].split('.')[0] == 'finance':
            spider1 = Spider1(t, link)
            #for i in range(1, 14):
            #    spider1.spider1(i)
            pool.map(spider1.spider1, range(1, 14))
        elif link.split('//')[1].split('.')[0] == 'society':
            spider1 = Spider1(t, link)
            #for i in range(1, 11):
            #    spider1.spider1(i)
            pool.map(spider1.spider1, range(1, 11))
        elif link.split('//')[1].split('.')[0] == 'ent':
            spider1 = Spider1(t, link)
            #for i in range(1, 9):
            #    spider1.spider1(i)
            pool.map(spider1.spider1, range(1, 9))
        elif link.split('//')[1].split('.')[0] == 'world':
            spider2 = Spider2(t, link)
            #for i in range(1, 6):
            #    spider2.spider2(i)
            pool.map(spider2.spider2, range(1, 6))
        elif link.split('//')[1].split('.')[0] == 'military':
            spider1 = Spider1(t, link)
            #for i in range(1, 7):
            #    spider1.spider1(i)
            pool.map(spider1.spider1, range(1, 7))
        elif link.split('//')[1].split('.')[0] == 'hm':
            spider1 = Spider1(t, link)
            #for i in range(1, 7):
            #    spider1.spider1(i)
            pool.map(spider1.spider1, range(1, 7))
        elif link.split('//')[1].split('.')[0] == 'tw':
            spider2 = Spider2(t, link)
            #for i in range(1, 9):
            #    spider2.spider2(i)
            pool.map(spider2.spider2, range(1, 9))
        elif link.split('//')[1].split('.')[0] == 'kpzg':
            spider1 = Spider1(t, link)
            #for i in range(1, 31):
            #    spider1.spider1(i)
            pool.map(spider1.spider1, range(1, 31))
    pool.close()
    end = time.time()
    print('Total time:', str(end - start))

if __name__ == '__main__':
    main()

mongodb_save.py

import pymongo

client = pymongo.MongoClient('localhost', 27017)
db = client['News']

def save_data(link, href, title, content, img):
    if img != 'Zero':
        img = 'http://' + link.split('//')[1].split('/')[0] + img[0]
    colls = link.split('//')[1].split('.')[0]
    collection = db[colls]
    collection.update_one({'标题' : title},
                          {'$setOnInsert':{'链接' : 'http://' + link.split('//')[1].split('/')[0] + href,
                                           '内容' : content,
                                           '图像链接' : img}},
                          upsert=True)

关键代码及流程分析

获取要闻部分中,各个模块的文本和链接,注意获取指定节点元素的文本和跳转链接URL时,因为HTML节点元素设置了过期时间,所以要先缓存至数据结构列表或字典,然后循环遍历列表或字典的URL。如果直接循环遍历节点元素的URL,那么在遍历过程中会因为超过过期时间,出现节点元素不存在的异常。

spider1,spider2函数负责请求对应新闻模块的URL,解析页面,抓取数据,保存至Mongodb数据库,save_data函数会保存在数据库中不存在的数据,对于已存在的数据不做保存。

创建进程池pool,map函数一次可以运行多个进程spider函数,实现一次爬取多页的数据。在pool中,当有一个进程执行完毕时,才能加入其它进程。

爬取的数据格式,文本说明如下:

代理池的建立及维护

由于代码量较多,这里只提供思维图并进行讲解。源代码地址:https://download.csdn.net/download/weixin_48913697/88640039

由于使用的是免费代理,该代理性能不稳定,所以有很多代理是失效的,可以使用付费代理,但是本人经费紧张,用不起付费代理,只能提供方案,不能保证代码能运行成功。如果有付费代理的,只需修改获取模块中的爬取代理逻辑,即在crawlers文件夹中加一个爬取付费代理的代码文件,在processors->getter.py文件中修改导入模块,指定crawlers中添加的爬取付费代理代码文件即可。

获取模块

负责请求代理网站爬取免费代理IP,在全局配置文件setting.py已设置每隔100秒运行一次获取模块。

Redis数据库

负责存储爬取的免费代理IP,并初始化代理分数为10,分数表示代理的可用状态,分值范围为0~100。在全局配置文件setting.py已设置数据库允许存储的代理总数,如果没有超过总数,则继续存储,否则不存储代理。

检测模块

负责检测数据库中代理的可用状态,设置一个检测链接来检测代理是否可用,如果可用,则直接置分为100分,否则分数减1,一旦减到0时,从数据库中删除该代理。在全局配置文件setting.py已设置每隔20秒运行一次检测模块,同时设置一次检测10个代理。

爬虫模块

负责从数据库中获取最高分数的随机代理,使用该代理请求URL,解析页面,爬取数据。当爬虫程序结束时,关闭进程3,中断进程1、2,整个主程序结束运行。

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值