一个极简的WebScraper爬取数据并用Pandas处理数据的案例

Tags
#爬虫 #Python

使用WebScraper爬取数据

首选先安装WebScraper这个Chrome插件:

网站的样式如下

notion image
网站url的正则匹配表达式为https://www.tuicool.com/articles/late?pn=[0-2],这里我的待读列表的分页只有0-2

设置要抓取的站点url

打开调试工具-WebScraper,添加新站点,输入名称和url的正则表达
notion image

添加selector选择要抓取的数据

输入id名,选择抓取的数据为Link,勾选Multiple支持多选,点击select,然后依次点击前两个标题即可全选本页的所有标题了,然后下方的点击Done selecting,一个数据抓取器就添加完成了。
notion image
此时可以点击 Data preview 查看是否真的有数据被选中了,弹出如下表格就是真的创建Selector成功了
notion image

开始抓取数据,并导出数据为csv文件

先点击Scrape抓取数据,它会自动新建浏览器窗口打开指定url,模拟真人查看网页。
如果url有点多的话,可能会稍稍要等一会。
过一会数据就抓好了,然后可以点击Browse查看抓取到的数据,最后点击'Export data as Csv',就可以将表格数据都导出为csv文件了。
notion image

导出的csv文件样式

文件内容如下:
notion image
我想将它转换成MarkDown格式的链接列表,类似下面这样,其实直接正则替换也行,但是那怎么考验真正的技术呢,所以我打算用python的库pandas来根据csv数据来导出这样的样式,这样就算以后有更复杂的场景,也都不在话下了。
- [软件架构分层,你的项目处于什么阶段?](https://www.tuicool.com/articles/ia2EvuN)
- [95% 的算法都是基于这 6 种算法思想](https://www.tuicool.com/articles/uqEzMjE)
- [中国程序员开发的远程桌面火了!Mac可用,只有9MB,支持自建中继器](https://www.tuicool.com/articles/nENJBnB)
- [从 Android 到 Java:如何从不同视角解决问题?](https://www.tuicool.com/articles/AfY7RnZ)

使用Pandas处理数据

安装anaconda

首选安装 Annaconda 这个Python集成开发软件,因为它自带了很多数据分析的模块,不用我们再去额外安装了,很省心。
至于安装过程中的一些配置,可以参考:【Anaconda教程01】怎么安装Anaconda3 - 知乎

启动jupyter

安装好了以后,直接命令行jupyter notebook启动jupyter,然后在打开的类似http://localhost:8888/tree/jupyter-notebook页面下(建议将此页面保存为书签,方便随时写代码),就可以新建python3环境的ipynb代码了。
Jupyter Notebook可以在网页页面中直接编写代码运行代码,每一个Block的代码的运行结果也会直接在代码块下显示。如在编程过程中需要编写MarkDown说明文档,可在同一个页面中直接添加Block来编写,便于作及时的说明和解释。类似这样的,就是一个Block。
notion image

Pandas读取csv文件并修改数据

import pandas as pd
import numpy as np
import re,os

path="~/Documents/MyObsidian/Cache/tuicoool.csv"

#filename可以直接从盘符开始,标明每一级的文件夹直到csv文件,header=None表示头部为空,sep=' '表示数据间使用空格作为分隔符,如果分隔符是逗号,只需换成 ‘,’即可。
df = pd.read_csv(path)

df['pageId'] = df['web-scraper-order'].str.replace(re.compile('([0-9]+)-([0-9]+)'),r"\1").astype('int')
df['elementId'] = df['web-scraper-order'].str.replace(re.compile('([0-9]+)-([0-9]+)'),r"\2").astype('int')

df.sort_values(by=['elementId'],na_position='first',inplace=True)

df=df[['pageId','elementId','article','article-href']]




# 准备输出Chrome书签格式的html文件,方便导入到各种书签工具    
out_path="/Users/yutianran/Documents/MyObsidian/Cache/tuicool.html"
chrome_template="""<!DOCTYPE NETSCAPE-Bookmark-file-1>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
  <DT><H3 ADD_DATE="1634759143" LAST_MODIFIED="1634759173" PERSONAL_TOOLBAR_FOLDER="true">书签栏</H3>
  <DL><p>
{LIST_ITEM}
  </DL><p>
</DL><p>
"""
dt_template="""        <DT><A HREF="ARTICLE_LINK" ADD_DATE="1634759157">ARTICLE</A>"""+"\n"

list_item_str=""
for idx,data in df[['article','article-href']].iterrows():
  dt_str=f"        <DT><A HREF=\"{data[1]}\">{data[0]}</A>\n"
  list_item_str=list_item_str+dt_str
chrome_str=chrome_template.replace("{LIST_ITEM}",list_item_str)
if os.path.exists(out_path):
  os.remove(out_path)
file = open(out_path, "w")                                                    
file.write(chrome_str)                                                  
file.flush()
file.close()
print(f"写入到html文件成功:{out_path}")

out_csv="/Users/yutianran/Documents/MyObsidian/Cache/tuicoool_sorted.csv"
if os.path.exists(out_csv):
  os.remove(out_csv)
df.to_csv(out_csv)
print(f"写入到csv文件成功:{out_csv}")

小笔记

Chrome书签格式

<!DOCTYPE NETSCAPE-Bookmark-file-1>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
  <DT><H3 ADD_DATE="1634759143" LAST_MODIFIED="1634759173" PERSONAL_TOOLBAR_FOLDER="true">书签栏</H3>
  <DL><p>
      <DT><A HREF="https://www.baidu.com/" ADD_DATE="1634759157">百度一下,你就知道</A>
      <DT><A HREF="https://www.zhihu.com/signin?next=%2F" ADD_DATE="1634759157">知乎 - 有问题,就会有答案</A>
  </DL><p>
</DL><p>

Python写入字符串到文件

if os.path.exists(out_path):
  os.remove(out_path)
file = open(out_path, "w")                                                    
file.write(chrome_str)                                                  
file.flush()
file.close()
print(f"写入到文件成功:{out_path}")

DataFrame做正则替换

df['pageId'] = df['web-scraper-order'].str.replace(re.compile('([0-9]+)-([0-9]+)'),r"\1").astype('int')

DataFrame截取指定行和列

print(df[0:5][['pageId','elementId','article','article-href']])

print(df[0:5])

print(df[['pageId','elementId','article']] )

print(df.to_string())

按行遍历DataFrame

for idx,data in df[['article','article-href']].iterrows():
  dt_str=f"<DT><A HREF=\"{data[1]}\">{data[0]}</A>\n"

字符串做正则替换

和DataFrame不太一样,不如DataFrame简洁
import re

url='http://www.55188.com/thread-8306254-2-3.html'
pattern='-(\d+)-(\d+)-(\d+)'
i=5678
newUrl=re.sub(pattern,lambda m:'-'+m.group(1)+'-'+str(i)+'-'+m.group(3),url)
print(newUrl)
notion image

参考资料


© fishyer 2022