文章目录

  • 一、项目概述
  • 二、项目实施
    • 1.导入所需要的库
    • 2.全局变量和参数配置
    • 3.产生随机时间和用户代理
    • 4.获取领导的fid
    • 5.获取领导所有留言链接
    • 6.获取留言详情
    • 7.获取并保存领导所有留言
    • 8.合并文件
    • 9.主函数调用
  • 三、结果、分析及说明
    • 1.结果说明
    • 2.改进分析
    • 3.合法性说明

一、项目概述

本项目主要是对领导留言板http://liuyan.people.com.cn/home?p=0内的所有留言的具体内容进行抓取,对留言详情、回复详情和评价详情进行提取保存,并用于之后的数据分析和进一步处理,可以对政府的决策和电子政务的实施提供依据。具体项目说明和环境配置可参考本系列的第一篇Python 爬取留言板留言(一):单进程版+selenium模拟。
本篇在第一篇的基础上做了一些改进

  1. 采用了多线程,设定同时运行的线程的数量为3,线程数量适中,这样在保证在同一时刻有多个线程在执行爬取的同时,也能避免线程过多对内存、CPU和网络带宽的高要求,从而大大降低了整体运行时间,这是该项目的主要改进。
  2. 对异常处理进行了优化,之前异常处理是放在获取一个领导对应的所有的留言链接函数里的,当获取不到加载更多按钮并且超时时就会抛出异常,这样使得如果异常发生在其他部分如获取留言详情时会被忽略,改进之后将其放入主函数,对于每一个领导都放入异常处理,这里涵盖了对该领导爬取时的所有操作,只要在任一环节报错都会捕捉到,同时增加了5层嵌套异常处理,增加了对出现异常的容忍度(在发生网络环境不好而加载不出页面、内存消耗较多而卡顿、被被爬取方反爬而不能爬取等情况时,可以对官员重新爬取以保证数据的完整程度和程序的健壮性)。

二、项目实施

由于在实现过程中有3种常用的方法实现多线程,因此对应也有3种不同的具体实现,这里选第1种进行说明:

1.导入所需要的库

import csv
import os
import random
import re
import time
import threadingimport dateutil.parser as dparser
from random import choice
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options

主要导入在爬取过程中需要用到的处理库和selenium中要用到的类。

2.全局变量和参数配置

# 时间节点
start_date = dparser.parse('2019-06-01')
# 控制同时运行的线程数为3
sem = threading.Semaphore(3)
# 浏览器设置选项
chrome_options = Options()
chrome_options.add_argument('blink-settings=imagesEnabled=false')

我们假设只爬取2019.6.1以后的留言,因为这之前的留言自动给好评,没有参考价值,因此设置时间节点,同时在全局中设置同时运行的线程数为3,并禁止网页加载图片,减少对网络的带宽要求、提升加载速率。

3.产生随机时间和用户代理

def get_time():'''获取随机时间'''return round(random.uniform(3, 6), 1)def get_user_agent():'''获取随机用户代理'''user_agents = ["Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)","Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)","Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)","Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)","Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)","Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)","Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1","Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0","Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5","Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20","Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)","Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)","Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1","Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre","Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11","Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10","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","Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1","Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36","Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20","Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,like Gecko) Version/5.1 Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)","Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"]# 在user_agent列表中随机产生一个代理,作为模拟的浏览器user_agent = choice(user_agents)return user_agent

产生随机时间并随机模拟浏览器用于访问网页,降低被服务器识别出是爬虫而被禁的可能。

4.获取领导的fid

def get_fid():'''获取所有领导id'''with open('url_fid.txt', 'r') as f:content = f.read()fids = content.split()return fids

每个领导都有一个fid用于区分,这里采用手动获取fid并保存到txt中,在开始爬取时再逐行读取。

5.获取领导所有留言链接

def get_detail_urls(position, list_url):'''获取每个领导的所有留言链接'''user_agent = get_user_agent()chrome_options.add_argument('user-agent=%s' % user_agent)drivertemp = webdriver.Chrome(options=chrome_options)drivertemp.maximize_window()drivertemp.get(list_url)time.sleep(2)# 循环加载页面try:while WebDriverWait(drivertemp, 50, 2).until(EC.element_to_be_clickable((By.ID, "show_more"))):datestr = WebDriverWait(drivertemp, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="list_content"]/li[position()=last()]/h3/span')).text.strip()datestr = re.search(r'\d{4}-\d{2}-\d{2}', datestr).group()date = dparser.parse(datestr, fuzzy=True)print('正在爬取链接 --', position, '--', date)if date < start_date:break# 模拟点击加载drivertemp.find_element_by_xpath('//*[@id="show_more"]').click()time.sleep(get_time())detail_elements = drivertemp.find_elements_by_xpath('//*[@id="list_content"]/li/h2/b/a')# 获取所有链接for element in detail_elements:detail_url = element.get_attribute('href')yield detail_urldrivertemp.quit()except TimeoutException:drivertemp.quit()get_detail_urls(position, list_url)

根据第4步提供的fid找到一个领导对应的所有留言的链接,由于领导的留言列表并未一次显示完,下方有一个加载更多按钮,如下
每次需要进行点击向下加载,所以要模拟点击的操作,向下滑动,等完全加载后再次点击,直到底部,有可能会滑倒页面最底部不再显示按钮或者由于被反爬或网络不好而未加载出来,此时定位元素会超时,增加异常处理,递归调用。
函数返回值时,不是一次返回一个列表,而是通过yield关键字生成生成器,按照程序执行的进度生成url,可以减少内存的压力。

6.获取留言详情

def get_message_detail(driver, detail_url, writer, position):'''获取留言详情'''print('正在爬取留言 --', position, '--', detail_url)driver.get(detail_url)# 判断,如果没有评论则跳过try:satis_degree = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_class_name("sec-score_firstspan")).text.strip()except:return# 获取留言各部分内容message_date_temp = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[6]/h3/span")).textmessage_date = re.search(r'\d{4}-\d{2}-\d{2}', message_date_temp).group()message_datetime = dparser.parse(message_date, fuzzy=True)if message_datetime < start_date:returnmessage_title = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_class_name("context-title-text")).text.strip()label_elements = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_elements_by_class_name("domainType"))try:label1 = label_elements[0].text.strip()label2 = label_elements[1].text.strip()except:label1 = ''label2 = label_elements[0].text.strip()message_content = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[6]/p")).text.strip()replier = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[1]/h3[1]/i")).text.strip()reply_content = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[1]/p")).text.strip()reply_date_temp = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[1]/h3[2]/em")).textreply_date = re.search(r'\d{4}-\d{2}-\d{2}', reply_date_temp).group()review_scores = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_elements_by_xpath("/html/body/div[8]/ul/li[2]/h4[1]/span/span/span"))resolve_degree = review_scores[0].text.strip()[:-1]handle_atti = review_scores[1].text.strip()[:-1]handle_speed = review_scores[2].text.strip()[:-1]review_content = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[2]/p")).text.strip()is_auto_review = '是' if (('自动默认好评' in review_content) or ('默认评价' in review_content)) else '否'review_date_temp = WebDriverWait(driver, 2.5).until(lambda driver: driver.find_element_by_xpath("/html/body/div[8]/ul/li[2]/h4[2]/em")).textreview_date = re.search(r'\d{4}-\d{2}-\d{2}', review_date_temp).group()# 存入CSV文件writer.writerow([position, message_title, label1, label2, message_date, message_content, replier, reply_content, reply_date,satis_degree, resolve_degree, handle_atti, handle_speed, is_auto_review, review_content, review_date])

我们只需要有评论的留言,因此在最开始要过滤掉没有评论的留言。然后通过xpath、class_name等方式定位到相应的元素获取留言的各个部分的内容,每条留言共保存14个属性,并保存到csv中。

7.获取并保存领导所有留言

user_agent = get_user_agent()
chrome_options.add_argument('user-agent=%s' % user_agent)
driver = webdriver.Chrome(options=chrome_options)
list_url = "http://liuyan.people.com.cn/threads/list?fid={}#state=4".format(fid)
driver.get(list_url)
try:position = WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath("/html/body/div[4]/i")).textprint(index, '-- 正在爬取 --', position)start_time = time.time()csv_name = position + '.csv'# 文件存在则删除重新创建if os.path.exists(csv_name):os.remove(csv_name)with open(csv_name, 'a+', newline='', encoding='gb18030') as f:writer = csv.writer(f, dialect="excel")writer.writerow(['职位姓名', '留言标题', '留言标签1', '留言标签2', '留言日期', '留言内容', '回复人', '回复内容', '回复日期', '满意程度', '解决程度分', '办理态度分','办理速度分', '是否自动好评', '评价内容', '评价日期'])for detail_url in get_detail_urls(position, list_url):get_message_detail(driver, detail_url, writer, position)time.sleep(get_time())end_time = time.time()crawl_time = int(end_time - start_time)crawl_minute = crawl_time // 60crawl_second = crawl_time % 60print(position, '已爬取结束!!!')print('该领导用时:{}分钟{}秒。'.format(crawl_minute, crawl_second))driver.quit()time.sleep(5)
except:driver.quit()get_officer_messages(index, fid)

获取该领导的职位信息并为该领导创建一个独立的csv用于保存提取到的留言信息,增加异常处理递归调用,调用get_message_detail()方法获取每条留言的具体信息并保存,计算出每个领导的执行时间。

8.合并文件

def merge_csv():'''将所有文件合并'''file_list = os.listdir('.')csv_list = []for file in file_list:if file.endswith('.csv'):csv_list.append(file)# 文件存在则删除重新创建if os.path.exists('DATA.csv'):os.remove('DATA.csv')with open('DATA.csv', 'a+', newline='', encoding='gb18030') as f:writer = csv.writer(f, dialect="excel")writer.writerow(['职位姓名', '留言标题', '留言标签1', '留言标签2', '留言日期', '留言内容', '回复人', '回复内容', '回复日期', '满意程度', '解决程度分', '办理态度分','办理速度分', '是否自动好评', '评价内容', '评价日期'])for csv_file in csv_list:with open(csv_file, 'r', encoding='gb18030') as csv_f:reader = csv.reader(csv_f)line_count = 0for line in reader:line_count += 1if line_count != 1:writer.writerow((line[0], line[1], line[2], line[3], line[4], line[5], line[6], line[7], line[8],line[9], line[10], line[11], line[12], line[13], line[14], line[15]))

将爬取的所有领导的数据进行合并。

9.主函数调用

多线程的实现主要在这部分,有3种方式实现:

  • 通过threading.Semaphore()指定线程数量,后边在实现作为线程参数的函数时使用上下文处理器
def main():'''主函数'''fids = get_fid()print('爬虫程序开始执行:')s_time = time.time()thread_list = []# 将所有线程加入线程列表,便于控制同时执行的线程数量for index, fid in enumerate(fids):t = threading.Thread(target=get_officer_messages, args=(index + 1, fid))thread_list.append([t, fid])for thread, fid in thread_list:# 5层嵌套进行异常处理try:thread.start()except:try:thread.start()except:try:thread.start()except:try:thread.start()except:try:thread.start()except:# 如果仍出现异常加入失败名单print('该官员爬取失败,已存入失败名单,以备再爬')if not os.path.exists('fid_not_success.txt'):with open('fid_not_success.txt', 'a+') as f:f.write(fid)else:with open('fid_not_success.txt', 'a+') as f:f.write('\n' + fid)continuefor thread, fid in thread_list:thread.join()print('爬虫程序执行结束!!!')print('开始合成文件:')merge_csv()print('文件合成结束!!!')e_time = time.time()c_time = int(e_time - s_time)c_minute = c_time // 60c_second = c_time % 60print('{}位领导共计用时:{}分钟{}秒。'.format(len(fids), c_minute, c_second))if __name__ == '__main__':'''执行主函数'''main()
  • 通过concurrent.futures.ThreadPoolExecutor指定线程数量,并调用submit()函数实现线程的调用执行
def main():'''主函数'''fids = get_fid()print('爬虫程序开始执行:')s_time = time.time()with ThreadPoolExecutor(3) as executor:for index, fid in enumerate(fids):# 5层嵌套进行异常处理try:executor.submit(get_officer_messages, index + 1, fid)except:try:executor.submit(get_officer_messages, index + 1, fid)except:try:executor.submit(get_officer_messages, index + 1, fid)except:try:executor.submit(get_officer_messages, index + 1, fid)except:try:executor.submit(get_officer_messages, index + 1, fid)except:# 如果仍出现异常加入失败名单print('该官员爬取失败,已存入失败名单,以备再爬')if not os.path.exists('fid_not_success.txt'):with open('fid_not_success.txt', 'a+') as f:f.write(fid)else:with open('fid_not_success.txt', 'a+') as f:f.write('\n' + fid)continueprint('爬虫程序执行结束!!!')print('开始合成文件:')merge_csv()print('文件合成结束!!!')e_time = time.time()c_time = int(e_time - s_time)c_minute = c_time // 60c_second = c_time % 60print('{}位领导共计用时:{}分钟{}秒。'.format(len(fids), c_minute, c_second))if __name__ == '__main__':'''执行主函数'''main()
  • 通过concurrent.futures.ThreadPoolExecutor指定线程数量,并调用map()函数实现函数和多个参数的映射来执行线程

def main():'''主函数'''fids = get_fid()print('爬虫程序开始执行:')s_time = time.time()with ThreadPoolExecutor(3) as executor:executor.map(get_officer_messages, range(1, len(fids) + 1), fids)print('爬虫程序执行结束!!!')print('开始合成文件:')merge_csv()print('文件合成结束!!!')e_time = time.time()c_time = int(e_time - s_time)c_minute = c_time // 60c_second = c_time % 60print('{}位领导共计用时:{}分钟{}秒。'.format(len(fids), c_minute, c_second))if __name__ == '__main__':'''执行主函数'''main()

主函数中先通过多线程获取领导所有留言,再合并所有数据文件,完成整个爬取过程,并统计整个程序的运行时间,便于分析运行效率。

三、结果、分析及说明

1.结果说明

3个完整代码和测试执行结果可点击https://download.csdn.net/download/CUFEECR/12199138下载,欢迎进行测试和交流学习,请勿滥用
整个执行过程相比于单线程大大缩短了时间,我选择了10个领导进行测试,它们的留言数量有差异,以便于发现多线程的优势,在云服务器中的运行结果分别如下











运行时间缩短到不到1小时半左右,约等于第一篇单线程的三分之一,因为同一时刻有3个子线程执行,大大降低了运行时间,效率比之前提高很多,加入多线程之后,可以让运行时间较长和较短的相互补充,同时多个线程同时运行,在同一时刻爬取多个领导,很显然大大缩短了运行时间。
最后得到了合并的DATA.csv:

可以进一步总结多线程的优势 :

  • 易于调度
  • 提高并发性:
    通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
  • 开销少:
    创建线程比创建进程要快,所需开销很少。
  • 利于充分发挥多处理器的功能:
    通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。

2.改进分析

(1)该版本的代码仍未实现自动爬取所有的fid,需要手动保存,是其中一点不足,可以在后期改进。
(2)爬取留言详情页仍然采用的selenium模拟,会降低请求效率,可以考虑用requests库请求。
(3)该版本对于反爬的措施较弱,因此很多时候会出现异常,比如得到的页面不正常找不到对应的元素,请求时间延长等,可以在之后的版本加入进一步的防反爬措施,进一步增加代码的健壮性。

3.合法性说明

  • 本项目是为了学习和科研的目的,所有读者可以参考执行思路和程序代码,但不能用于恶意和非法目的(恶意攻击网站服务器、非法盈利等),如有违者请自行负责。
  • 本项目所获取的数据都是在进一步的分析之后用于对电子政务的实施改进,对政府的决策能起到一定的参考作用,并非于恶意抓取数据来攫取不正当竞争的优势,也未用于商业目的牟取不法利益,运行代码只是用几个fid进行测试,并非大范围地爬取,同时严格控制爬取的速率、争取不对服务器造成压力,如侵犯当事者(即被抓取的网络主体)的利益,请联系更改或删除。
  • 本项目是留言板爬取系列的第二篇,后期会继续更新,欢迎读者交流,以期不断改进。

Python 爬取留言板留言(二):多线程版+selenium模拟相关推荐

  1. Python爬取PPT模板(requests+BeautifulSoup+多线程)

    Python爬取PPT模板(requests+BeautifulSoup+多线程) 快到做毕业设计的时间了,得去找点好看的PPT模板了,在http://www.ypppt.com这个网站上发现了很多不 ...

  2. python爬取虎扑评论_python爬虫系列Selenium定向爬取虎扑篮球图片详解

    前言: 作为一名从小就看篮球的球迷,会经常逛虎扑篮球及湿乎乎等论坛,在论坛里面会存在很多精美图片,包括NBA球队.CBA明星.花边新闻.球鞋美女等等,如果一张张右键另存为的话真是手都点疼了.作为程序员 ...

  3. python爬取bilbili信息(二)

    今天是第二部分 在上一部分,我们已经将信息提取的思想做了大致的分析,现在我们就来爬取我们所需要的信息.首先,我把咱们所需要的代码,放在这里.然后逐个讲解. from typing import Lis ...

  4. python爬取自如房间信息(二)

    主要是针对自如房价的爬取 .以下代码对房价图片进行处理,将里面的数字提取出来,然后用knn最近邻算法去对图片上的数据进行分类. import sys import cv2 import numpy a ...

  5. Python 爬取火车票信息(易于理解版)

    本文讲解的是通过Python语言实现12306火车票信息爬取的实例 主要思路为:通过查询接口获取网页信息 →  找出信息中的规律 → 对信息进行处理(主要是对字符串的处理) → 提炼相关信息 → 输出 ...

  6. python 爬取某我音乐【简易版】

    爬取某我音乐[升级版] ```python import requests,json import prettytable as ptname = input("输入歌手名字:") ...

  7. python爬取bilibili数据_python基础教程之selenium+phantomjs爬取bilibili

    selenium+phantomjs爬取bilibili 首先我们要下载phantomjs 你可以到 http://phantomjs.org/download.html 这里去下载 下载完之后解压到 ...

  8. python多线程爬虫 爬取多个网页_python多线程爬虫爬取顶点小说内容(BeautifulSoup+urllib)...

    思路 之前写过python爬取起点中文网小说,多线程则是先把爬取的章节链接存到一个列表里,然后写一个函数get_text每次调用这个函数就传一个章节链接,那么就需要调用n次该函数来获取n章的内容,所以 ...

  9. python爬取自如房间信息(一)

    使用python和selenium+Chrome Headless爬取自如房间信息,并将结果存储在MongoDB中.其中最麻烦的应该是每间房的价格,因为自如是用一张图片和offset来显示价格,所以不 ...

最新文章

  1. element-ui 左侧边栏el-menu组件: 路由跳转 - 案例篇
  2. ABBYY FineReader 12PDF选项卡之图像及文字设置
  3. Python机器学习:多项式回归与模型泛化010L1L2和弹性网络
  4. SpringCloud学习笔记024---SpringBoot中使用大部分公用的配置记录
  5. smarty课程---smarty的处理过程是怎样的
  6. centos6.5 tomcat开机启动
  7. 从写组件说Xml——实现(五)
  8. radius认证服务器部署linux,CentOS安装配置radius服务器
  9. 走近CTPN:1. 解读README
  10. 高德地图,根据经纬度定位到某个地方(位置标注)
  11. 网课答案接口 查题系统
  12. 《极客与团队》一HRT实战
  13. 主流各云平台主机性能对比
  14. vela和鸿蒙,小米Vela系统发布,将对标华为鸿蒙OS
  15. 基于springboot项目中使用docker-compose+es+kibana+logstash+mysql 提高数据查询效率
  16. emacs 常用命令与配置
  17. unity3d培训_005
  18. 计算机四年级上册语文教案,人教版四年级上册语文教案
  19. 众贷网满月死亡 P2P网贷业将现倒闭潮?
  20. mysql:In aggregated query without GROUP BY, expression #1 of SELECT list contains...........

热门文章

  1. 用虚拟信用卡注册Google Play开发者账号
  2. 苹果电脑传android文件怎么打开,怎么用苹果电脑给android手机传文件
  3. ANN(人工神经网络)基础知识
  4. FreeBSD开发手册(一)
  5. java多线程------锁
  6. 520、Java Spring Cloud Alibaba -【Spring Cloud Alibaba Zuul】 2021.11.02
  7. python中frame用法_Python实例之wxpython中Frame使用方法
  8. 文字太多时给文本框添加滑动条——text + ContentSizeFitter + Scroll View
  9. Python在游戏中的热更新
  10. Elasticsearch 时间类型总结