它只有38行代码,而且我以前还没有这么多地使用过网络抓取。
而且,我也不知道这样做的效率有多高(现在我甚至不知道文件是否存在,而且每次运行程序时我都会覆盖它,所以如果我的代码中途中断,我就必须再次运行它,它就会从头开始下载所有文件)。我必须解决这个问题)。
但无论如何,这是代码:
# Scrapes all pdfs off from www.annualreports.com
# Haven't tested yet but should be somewhere around 70,963 pdfs since my empty search returned 5,479/5,674 stated companies
import requests
from urllib.parse import urljoin
import pandas as pd
from bs4 import BeautifulSoup as bs
import os, re
import pickle
def extract_table():
r = requests.get('http://www.annualreports.com/Companies?search=')
soup = bs(r.content, 'lxml')
df = pd.DataFrame([(i.text, 'http://www.annualreports.com' + i['href']) for i in soup.select('tbody td:nth-of-type(1) a')], columns = ['Company','Link'])
df.to_pickle('links.pkl') # saves into a dataframe the name of the company plus the href link it points to
def scrap_pdfs():
df = pd.read_pickle('links.pkl')
a = 0 # for naming the filenames numerically
for x in range(df.Link.count()):
url = df['Link'][x] # reads the "Link" column from the dataframe
folder_location = r'/home/duke/Annual_Reports/Data' # SPECIFY FULL DIRECTORY
response = requests.get(url)
soup= bs(response.text, "html.parser")
for link in soup.select("a[href$='.pdf']"): #goes through all the .pdfs in all of the href links
#filename = os.path.join(folder_location, ['href'].split('/')[-1]) # Names the pdf files using the last portion of each link
filename = os.path.join(folder_location, str(a))
a+=1
with open(filename, 'wb') as f:
f.write(requests.get(urljoin(url,link['href'])).content)发布于 2019-09-18 00:12:11
是的,现在这将效率低下,我肯定地说,使用可预测的文件名将是这里的第一个关键更改,如果链接目标或描述不能作为文件名的一部分使用,请考虑对其进行散列。简单地列举所有链接是次优的:如果,即使以前的文件保存在周围而不是覆盖,在运行之间运行网站的内容更改(看起来很有可能,不是吗?)突然间,下载文件的顺序与磁盘上的顺序不匹配?一定要做点什么。
第二,代码将创建那个泡菜文件分开,因为它应该多次运行?有点奇怪,但作为一个临时数据库,为什么不呢?我通常认为泡菜文件是短暂的,因为格式是(曾经?)特定于Python。
然后,只需检查文件是否存在并跳过它(也可能检查它是否为非空文件;在下载完整数据之前,还可以对返回内容大小的HTTP头进行比较,然后再实际下载完整文件)。
数据框架上的range应该更简单,但现在我无法找到更简单的方法(不是使用索引,而是简单地遍历值本身)。
f.write(requests.get(...).content) -我认为这会在内存中缓冲完整的文件。最好不要这样做,相反,requests可能有一些工具可以直接写入文件(或类似文件的对象),或者下载的内容必须逐个读取到一个小缓冲区中,并将其与将该缓冲区写入输出文件交替。
最后,格式可以更一致(大部分表达式之间的空格)。看一看PEP8,或者是一个自动格式化器,就可以自动做到这一点。另外,还应该删除剩余的注释。
对,所以总的来说它是有效的,但是对于生产代码来说,有很多事情可以做,特别是使它成为一个更加充实的脚本(读:解析命令行参数,为输出目录提供默认参数;等等)。解析很好,选择器也很简洁,易于阅读。
https://codereview.stackexchange.com/questions/229071
复制相似问题