Python爬取豆瓣网中搜索的指定内容

《Python爬取豆瓣网中搜索的指定内容》

如上图,当前我想要爬取豆瓣的小组中,涉及到意大利留学内容的所有的小组标题和对应的URL。这里利用 Python 脚本,分别使用两种方式爬取我需要的内容。两个脚本分别如下:

使用 selenium 模块爬取

# -*- coding: utf-8 -*-
# python3.6
import csv
import time
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class DouBan:
    def __init__(self, search_field):
        self.search_filed = search_field
        self.url = 'https://www.douban.com/search?cat=1019&q={}'.format(self.search_filed)
        self.result_data = {}

    def get_data(self):
        driver = webdriver.Chrome()
        driver.get(self.url)
        wait = WebDriverWait(driver, timeout=2, poll_frequency=0.5)
        # 如果不使用向url添加搜索字段的方式,也可以使用以下两行注释代码的这种方式,让selenium自动输入内容进行搜索
        # driver.find_element_by_xpath("//input[@placeholder='搜索你感兴趣的内容和人']").send_keys('意大利留学'.decode('utf-8'))
        # driver.find_element_by_xpath("//input[@placeholder='搜索你感兴趣的内容和人']").send_keys(Keys.RETURN)

        # 通过selenium模拟浏览器向下不断翻页并自动点击‘显示更多’按钮,让网页加载显示搜索到的全部网页数据
        while True:
            try:
                time.sleep(1)
                wait.until_not(EC.presence_of_element_located((By.NAME, "style")))
                driver.find_element_by_link_text("显示更多").click()
            except:
                break

        # 将网页全部加载的数据使用bs4模块解析到需要的数据并添加到字典中
        response = driver.page_source
        soup = BeautifulSoup(response, "html.parser")
        result = soup.find_all('div', {'class': 'result'})
        for line in result:
            title1 = line.div.a['title']
            title_url = line.div.a['href']
            self.result_data[title1] = title_url

    def write_csv(self):
        if self.result_data:
            line_info = [[i, j] for i, j in self.result_data.items()]
            with open('result.csv', 'w', newline='', encoding='utf-8-sig') as csvfile:
                writer = csv.writer(csvfile)
                writer.writerows(line_info)
        else:
            print('需要写入的数据为空')


if __name__ == '__main__':
    crawl_db = DouBan('意大利留学')
    crawl_db.get_data()
    crawl_db.write_csv()

脚本说明:
因为豆瓣网站中使用了 Ajax 技术来显示网页中的内容,通过使用 selenium 模块来模拟鼠标不断向下滑动页面,并自动点击「显示更多」,一直加载搜索到的所有网页内容:
《Python爬取豆瓣网中搜索的指定内容》

判断什么时候加载完所有数据,主要使用了「显示更多」的代码进行判断:
「显示更多」的代码:

<a href="#more" class="j a_search_more" data-q="意大利留学" data-start="20" data-cat="2012">显示更多</a>

最后加载完所有的数据后,「显示更多」的代码:

<a href="#more" class="j a_search_more" data-q="意大利留学" data-start="20" data-cat="2012" title="显示更多" style="display: none;">显示更多</a>

使用 requests 模块爬取

# -*- coding: utf-8 -*-
# python3.6
import re
import csv
import json
import requests
from urllib.parse import urlencode


class DouBan:
    def __init__(self, search_field, search_position=0, search_type=1019):
        """
        :param search_field: 豆瓣搜索框中要搜索的字段
        :param search_position: 请求的偏移量,一次请求20条记录,值不断累加,默认值从0开始
        :param search_type: 豆瓣中搜索分类,搜索全部的值是1015,这里只想在豆瓣的小组分类中搜索字段值为1019
        """
        self.params = {
            'q': search_field,
            'start': search_position,
            'cat': search_type
        }
        self.base_url = 'https://www.douban.com/j/search?'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36'
        }
        self.url_list = []
        self.result_data = {}

    def page_url(self):
        first_url = self.base_url + urlencode(self.params)
        response = requests.get(first_url, headers=self.headers)
        if response.status_code == 200:
            response_preview = json.loads(response.text)
            if response_preview['more'] is True:
                total_page = int(response_preview['total'] / 20) + 1
                for i in range(total_page):
                    self.url_list.append(self.base_url + urlencode(self.params))
                    self.params['start'] += 20
                return self.url_list
            else:
                self.url_list.append(self.base_url + urlencode(self.params))
                return self.url_list

    def page_data(self, url):
        try:
            response = requests.get(url, headers=self.headers)
            if response.status_code == 200:
                response_data = json.loads(response.text)
                for i in response_data['items']:
                    result = re.compile(r'<a class=.*? href="(.*?)" target=.*? title="(.*?)">', re.M).search(i)
                    title1 = result.group(2)
                    title_url = result.group(1)
                    self.result_data[title1] = title_url
        except Exception as e:
            print(e)

    def write_csv(self):
        if self.result_data:
            line_info = [[i, j] for i, j in self.result_data.items()]
            with open('result.csv', 'w', newline='', encoding='utf-8-sig') as csvfile:
                writer = csv.writer(csvfile)
                writer.writerows(line_info)
        else:
            print('需要写入的数据为空')


if __name__ == '__main__':
    crawl_db = DouBan('意大利留学')
    url_list = crawl_db.page_url()
    for u in url_list:
        crawl_db.page_data(u)
    crawl_db.write_csv()

脚本说明:
使用 Chrome 浏览器分析请求 url 参数:
《Python爬取豆瓣网中搜索的指定内容》
从截图中能看到 url 的请求参数,经过多次请求发现,可变的参数有三个,分别是 q、start、cat。其中 q 是搜索字段值,在这里是我要搜索的「意大利留学」,start 显示内容的偏移量一次叠加 20,默认从 0 开始,cat 是搜索分类,这里是表示的是小组。使用 urlencode() 方法将这三个参数转化为 URL 的 get 请求参数,然后使用 requests 模块的 get 方法来请求 URL 的内容。

最后爬取的内容,是写入到csv文件中。部分结果展示如下:
《Python爬取豆瓣网中搜索的指定内容》

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注